* → CV Array
The one-wire bridge into 470 low-level OpenCV functions
- input
- nparray
ComfyUI pipes IMAGE tensors, MASK tensors and LATENT dicts. OpenCV wants a numpy array, or it wants nothing. This pack's entire low-level half - some 470 auto-generated wrappers of cv2.* functions - speaks in a raw ndarray the pack types as NPARRAY, so at some point you need a converter, and this is the one that doesn't ask questions about what you plugged in.
Why you'd reach for it
It auto-detects the input type and hands back a plain NPARRAY:
IMAGE→ uint8 BGR[H,W,3]MASK→ uint8[H,W]LATENT→ float32[H,W,C], values untouched, still in latent spaceNPARRAY→ passed straight through
Note the BGR. ComfyUI's tensors are RGB; OpenCV's functions - and the pack's low-level wrappers - assume BGR. Getting that conversion for free is half of why this node exists.
The other half is subgraph boundaries. If you're building a reusable subgraph whose input socket must accept "whatever the caller has", the * wildcard input is the only way to do it, and this node is what you put immediately behind the wildcard to make the value usable. For a normal graph, though, reach for the specific converters instead: Image → CV Array, Mask → CV Array, Latent → CV Array and their inverse directions all exist, and they expose real options (color_format, dtype, batch_index) that this node deliberately doesn't. Those three knobs are exactly what you need when the generic default is wrong - a Canny or threshold wants single-channel GRAY, not BGR, and a float32 image is what a subpixel operation wants.
The inputs and outputs
input-NPARRAY,IMAGE,MASKorLATENT. That's it. One input, one output, no settings.- Output
nparray- the raw ndarray, as described above.
The catch that matters: frame 0 only
An IMAGE batch becomes one image. Only frame 0 is converted; the rest are dropped silently. For a single still that's exactly right and it's what you want - raw cv2 functions operate on one image. For a 120-frame clip it means you get frame 0's result and might not notice. If you're processing video, that's what CV Unstack Batch (single frames as a ComfyUI list) and the high-level batch-aware nodes are for.
Latents come through in latent space. A float32 [H,W,C] array of latent samples is not an image: run a denoiser over it and you're smoothing noise in a codec, not in a picture. This is genuinely useful - measuring latent statistics, doing arithmetic across a latent batch, feeding something that expects raw numbers - but as a debugging move. If you wanted pixels, decode first.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
then restart ComfyUI, or use Manager → ComfyUI CV. The dependency list is short and honest: opencv-contrib-python-headless~=5.0.0.93, numpy, torch. Behaviour is curated against that pinned OpenCV version. This particular node needs no contrib at all, but the pack as a whole does - all four OpenCV wheel flavours share a single site-packages/cv2, so installing plain opencv-python over the contrib wheel empties the contrib submodules and the xphoto/ximgproc nodes disappear (tools/repair_opencv_contrib.py --check shows it, --apply repairs it). Python 3.12+ and the V3 node API are both required.
Traps
- The wildcard hides types by design. The KB's plumbing notes have a long argument about type-erasing utility nodes: they make a graph easy to wire and hard to debug, because the engine can't tell you that you plugged a
LATENTinto something expecting pixels. Use it at boundaries where a wildcard is genuinely needed, not everywhere it fits. - Masks and images are not interchangeable downstream.
MASK → uint8 [H,W]andIMAGE → uint8 BGR [H,W,3]are different shapes, and a low-level wrapper that wants three channels will promote the mask for you (some of them do) or produce something strange (others). Read the specific node's tooltip before assuming. - Values are not rescaled. A
MASKthat was 0.0–1.0 in float comes out as uint8 0/255; a float image stays float if you used the typed converter and asked for float32. There's no automatic normalisation, on purpose - a wrapper that silently stretched your data would be worse than one that doesn't.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| input | NPARRAY,IMAGE,MASK,LATENT | IMAGE, MASK, LATENT or NPARRAY to convert to a raw ndarray. A LATENT link is processed in latent space: frame 0 becomes a float32 [H,W,C] array (any channel count), values untouched. Arithmetic ops (add, multiply, etc.) also accept a full LATENT batch ({samples: [B,C,H,W]}) — the whole batch flows through when both inputs have the same batch size. 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)
| Name | Type | Description |
|---|---|---|
| nparray | NPARRAY | Raw ndarray: uint8 BGR [H,W,3] from IMAGE, uint8 [H,W] from MASK, float32 [H,W,C] from LATENT, or the NPARRAY as-is. |