cv2.imdecode
When the image arrives as bytes, not as a file
- buf
- nparray
cv2.imdecode takes an encoded image in memory - the actual PNG or JPEG bytes - and hands you back decoded pixels. That is narrower than it sounds, and the narrowness is intentional: this pack deliberately does not expose cv2.imread, because imread takes a filesystem path, which would let any downloaded workflow read any file on your machine. The hidden-functions list in the source says it plainly: cv2.imdecode is not in the path-based blacklist because it decodes an in-memory buffer, no path.
So the practical question is who gives you bytes. In a normal workflow: nobody, and you should use core's Load Image, which already decodes through PIL/torch. This node earns its place when the image arrives from somewhere that is not the disk - an API node returning a JPEG blob, a database or memory buffer from a custom node, a byte stream you assembled yourself.
How it works
cv2.imdecode(buf, flags). The buffer must be a 1-D array of bytes; OpenCV sniffs the format from the content itself (PNG, JPEG, WebP, TIFF, BMP and friends), so there is no extension to get wrong. The decoded result comes back as a normal pixel array.
The flags dropdown is the other half of the node's usefulness, and it is a genuinely better menu than the usual "colour or not":
IMREAD_COLOR- the default, 3-channel BGR. Note the channel order: OpenCV's convention is BGR, and the pack's conversion nodes handle the swap when you turn the array back into an IMAGE.IMREAD_GRAYSCALE- decode to a single channel directly. Better than decoding in colour and converting, both in speed and in accuracy.IMREAD_UNCHANGED- keep everything: alpha channel and original bit depth. This is how you get an RGBA or 16-bit image that a colour decode would have flattened. If you are carrying transparency or high bit depth through a CV pipeline, this is the flag.IMREAD_ANYDEPTH,IMREAD_ANYCOLOR- the "do not throw data away" pair, and the dropdown also offers the common combined formIMREAD_COLOR | IMREAD_ANYDEPTH.IMREAD_REDUCED_COLOR_2/_4and the grayscale equivalents - decode at half or quarter scale. On JPEG this is nearly free (the decoder just stops refining high-frequency coefficients); on PNG expect a live decode plus a downsample.IMREAD_IGNORE_ORIENTATION- skip the EXIF rotation. Relevant if you care about orientation and are used to libraries applying it silently.
The two inputs, and the output that matters
buf- the encoded bytes as an NPARRAY. The socket's generic note advertises IMAGE/MASK/NPARRAY, but the data has to be an encoded byte stream. An IMAGE link carries already-decoded pixels, which is not a container format: cv2 will find nothing to decode and you get an empty result, not a helpful message about the type being wrong. That is the single trap in this node.flags- as above.- Output
nparray- the decoded image, or nothing when the bytes were not a decodable image. Treat "empty" as a possibility in your graph: check withInspect CV Data(shape and dtype) before wiring it into a conversion node that assumes three channels.
Getting the result into the rest of the graph is a conversion: CV Array → Image (with its channel-order setting for BGR→RGB) for an IMAGE socket, or straight into the low-level cv2.* nodes to stay in array space. The reverse - an image out to encoded bytes - is not something this pack does; nothing here writes files or touches the filesystem, on purpose.
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 and a recent ComfyUI on the V3 node API. The pinned OpenCV wheel is the only dependency; the pack ships no models and no image codecs of its own.
When it goes wrong
- An IMAGE is wired in and the output is empty. Expected, as above. Decoded pixels are not encoded bytes; there is no conversion that makes this work - feed the node a byte buffer or use Load Image instead.
- The datatype looks wrong. A numpy
float32array of pixel values is not a PNG. The buffer has to be uint8 bytes; if you built one yourself, check withInspect CV Data. - Colours come out swapped. OpenCV decodes to BGR. Anything that treats the array as RGB will show you red and blue exchanged - the fix is the channel-order option on the conversion node, not a
cvtColorguess. - Alpha vanished. You used
IMREAD_COLOR; switch toIMREAD_UNCHANGED. - Nothing decodes and no error is raised. cv2's decode failures are quiet by design: you get no image rather than an exception. Gate on the result being non-empty (a shape check via
Inspect CV Data) instead of assuming pixels arrived. - Wheel hygiene, one more time. All four OpenCV distributions share one
site-packages/cv2; another pack installing a non-contrib wheel can strip contrib modules and make nodes disappear.tools/repair_opencv_contrib.py --check/--applyin the pack repo is the fix.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| buf | NPARRAY,IMAGE,MASK | Input array or vector of bytes. 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. | |
| flags | COMBO | IMREAD_COLOR | Flag that can take values of cv::ImreadModes. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| nparray | NPARRAY | — |