Nodes/ComfyUI CV/cv2.imdecode
ComfyUI Node

cv2.imdecode

When the image arrives as bytes, not as a file

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.imdecode
  • buf
  • nparray
◄flagsIMREAD_COLOR►

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 form IMREAD_COLOR | IMREAD_ANYDEPTH.
  • IMREAD_REDUCED_COLOR_2/_4 and 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 with Inspect 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 float32 array of pixel values is not a PNG. The buffer has to be uint8 bytes; if you built one yourself, check with Inspect 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 cvtColor guess.
  • Alpha vanished. You used IMREAD_COLOR; switch to IMREAD_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 / --apply in the pack repo is the fix.
Categoryimage/CV/low-level/cv2 I

Inputs (2)

NameTypeDefaultDescription
bufNPARRAY,IMAGE,MASKInput 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.
flagsCOMBOIMREAD_COLORFlag that can take values of cv::ImreadModes.

Outputs (1)

NameTypeDescription
nparrayNPARRAY—