Nodes/ComfyUI CV/CV Batch → Image Batch
ComfyUI Node

CV Batch → Image Batch

B frames out of a cv2 loop? Here's the way back onto the canvas

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
CV Batch → Image Batch
  • nparray
  • image
  • alpha
◄channel_orderBGR (OpenCV default)►

What it's for

This is the exit door. The pack's bridge set is three nodes and a rule: CV Image → CV gets you into OpenCV-land, CV Image Batch → CV Batch gets a whole batch in, and this one turns a batched numpy array back into a ComfyUI IMAGE batch so the rest of the graph - a save, a VAE encode, an upscaler, another model - can see it.

You'll reach for it any time you've been doing cv2 work across frames: a raw cv2_* wrapper over a batch, a filter you ran per frame, arithmetic between two batches, an optical-flow pass. The result of that work is a numpy array, and nothing downstream accepts a numpy array.

How it works

It takes [B,H,W,C] or [B,H,W] and produces a ComfyUI IMAGE batch: float32, RGB, 0..1. The channel_order dropdown decides how honest the conversion is about your data.

  • BGR (OpenCV default) - the standard cv2→IMAGE conversion: BGR swapped to RGB, uint8 mapped to float32 over 0..1. Right for anything a normal cv2 function produced.
  • RGB - skips the channel swap and clamps to 0..1, for data that's already RGB-ordered. Both BGR and RGB round-trip through uint8, so you're not escaping quantisation by picking the other one.
  • RAW - no conversion at all. Values pass through as-is. This is the mode for HDR data, radiance maps and arithmetic results that legitimately live outside 0..1, and it's the one to use when clamping would destroy the number you care about.

Four-channel input is handled properly: BGRA comes back as an IMAGE plus a separate alpha MASK. For RGB/BGR input the alpha output still exists and is all-255 - fully opaque - so wiring it does nothing surprising.

There's one shape ambiguity worth memorising, because it's the kind of thing that produces a beautiful result that's completely wrong. A 3-D [H,W,C] array is read as a [B,H,W] grey batch. If you have a single colour frame, use CV Array → Image instead; if you have a mask, a single [H,W] gets wrapped into a one-frame batch and comes through fine.

Outputs

  • image - the batch, float32 RGB 0..1 (RAW mode may exceed that range).
  • alpha - the alpha as a MASK batch when a BGRA input had one.

The alpha does not get reattached to anything. If you want it, wire it; if you ignore it, your transparency is gone.

Install

ComfyUI Manager, search ComfyUI CV. By hand:

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv

Restart afterwards. Requirements: Python ≥ 3.12, a ComfyUI recent enough to have the V3 node API, and the contrib OpenCV wheel:

pip install "opencv-contrib-python-headless~=5.0.0.93"

Where people get burned

Red and blue swapped means you converted twice. Classic version: cv2 gives you BGR, you run cv2_cvtColor to RGB upstream, then this node swaps again because it's still set to BGR. ComfyUI's IMAGE is RGB; OpenCV's default is BGR; pick exactly one place in the chain where that swap happens.

RAW is a trap if you wanted a picture. It's the right mode for float data, and completely wrong as a "just show me the array" option - nothing gets scaled to 0..1, so values at 3.7 are already clipped by the time anything displays them. If the output looks like a white rectangle, you probably wanted normalize in a preview node, not RAW here.

BGR mode clips. It's mapping to the 0..1 range, so out-of-range floats get clamped. If you've done arithmetic between two images and the result legitimately exceeds 1.0, that mode is throwing away the interesting part.

Two bridge nodes, two directions, easily confused. CV Array → Image (single frame, including single colour frames) and CV Batch → Image Batch (this one) are different nodes in the same file. Feeding a single 3-D frame here gives you a grey batch, which is a real conversion and not an error - and it will absolutely look like a bug.

Large batches are real memory. Every frame gets a float32 tensor; a 300-frame 1080p batch through this node is not a small allocation. Convert close to where you need it rather than leaving 300 frames of float32 sitting in the graph.

Categoryimage/CV/low-level

Inputs (2)

NameTypeDefaultDescription
nparrayNPARRAYBatched ndarray: [B,H,W,C] or [B,H,W]. A single [H,W] mask is wrapped to a one-frame batch; a 3-D [H,W,C] single frame is read as a [B,H,W] gray batch — use 'CV Array → Image' for single color frames.
channel_orderCOMBOBGR (OpenCV default)How to interpret 3/4-channel data. BGR: standard cv2→IMAGE conversion (BGR→RGB, uint8→float32 0..1). RGB: skip channel swap, clamp to 0..1 — for float32 BGR from cv2 arithmetic where values stay in range. RAW: no conversion at all, values as-is — for HDR or arithmetic results outside 0..1.

Outputs (2)

NameTypeDescription
imageIMAGEIMAGE batch [B,H,W,C] float32 RGB 0..1 (RAW mode may exceed 0..1).
alphaMASKAlpha MASK batch from BGRA input (all-255 opaque when input is RGB/BGR).