CV Concat Arrays
The join that gives you cv2.merge back
- array1
- array2
- array3
- array4
- nparray
- length
What this is for
Splitting an array is furniture in this pack - CV Split Channels, cv2.extractChannel, CV Take By Index all pull things apart. Putting them back was, until this node, impossible. cv2.merge, cv2.hconcat and cv2.vconcat all take a vector<Mat>, and the pack's auto-generated wrappers can't express a vector-of-mats argument, so none of them exist as cv2_* nodes. The shipped split-channels subgraphs were one-way. CV Concat Arrays is the return leg.
Two everyday jobs: append two detection tables or two point sets (axis 0), and merge channels back together after a split (axis one past the end - see below).
How it works
Everything hinges on axis, which is a normal negative-indexable axis except for one case that isn't normal at all:
axis 0- append rows. Two detection tables, two point sets, two frames of samples.axis 1- side by side, columns.axis -1- the last axis, which is what you use with arrays that already have a channel axis.- one past the end (axis 2 for
(H, W)input) - stacks a new last axis. That'scv2.merge: three(H, W)planes become one(H, W, 3)image. This is the setting the split → merge round trip needs, and a plain concatenate would instead glue the planes side by side into a(H, W*3)smear. The tooltip calls this out because it's the one place where the node's axis behaves unlike numpy's.
Orthogonally, note that the inputs need only agree on the axes other than the concat axis - that's the whole difference from CV Stack Batch, which adds a new leading axis and wants its inputs to match exactly.
There are three design choices here worth knowing because they're all "don't fail": empty inputs contribute nothing (an empty detection set appended to a non-empty one is a no-op rather than an error), mixed dtypes get promoted the numpy way (uint8 + float32 → float32), and genuine shape mismatches raise with a message naming the inputs, their shapes and the axis they differ on. That last one is a feature - silently broadcasting to the wrong shape is how you get a mask of the wrong size ten nodes later.
Inputs and outputs
array1 and array2 are required, array3 and array4 are optional and appended in order; axis (default 0, range -8 to 8) is the only parameter. Outputs are nparray, the joined array, and length, the size along the concat axis - which pairs neatly with CV Take By Index when you want to split the result back apart, since you now know how long it is.
If you need control over the resulting dtype rather than numpy's promotion rules, cast first with CV Cast Array.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
# restart ComfyUI
Or search ComfyUI CV in ComfyUI Manager (publisher bmad4ever). Needs Python ≥ 3.12, a V3-node-API ComfyUI, and opencv-contrib-python-headless~=5.0.0.93 from the pack's requirements. Nothing to download - this one is numpy concatenate with better error messages.
Common issues
- "Cannot concatenate along axis 0: ... differ on axis 1". Your two arrays aren't the same shape off the concat axis. The message tells you which axis and both shapes, which is more than numpy does - read it before reshaping blindly.
- Channels came out side by side instead of stacked. You used
axis -1(or 1) on(H, W)planes. For the merge round trip you want one past the end. (0, 1, 2)shapes are confusing you. Afound=falsenode upstream emits an empty array rather than nothing, and this node treats empty as "contribute nothing" - so an empty detection table appended to a real one just gives you the real one back. Usually what you want; occasionally the reason a count is lower than you expected.- Contrib nodes disappeared from the pack. A non-contrib OpenCV wheel emptied the contrib submodules in the shared
site-packages/cv2.python tools/repair_opencv_contrib.py --check/--apply.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| array1 | NPARRAY | First array. Its number of dimensions and its sizes on every axis EXCEPT the concat axis must match the others. | |
| array2 | NPARRAY | Second array, appended after the first. | |
| axis | INT | 0-8–8 | Which axis to join along. 0 = rows (append), 1 = columns (side by side), -1 = the last axis (merge arrays that already have a channel axis). Negative counts from the end. ONE PAST the end - axis 2 for (H,W) inputs - stacks a NEW last axis instead, which is cv2.merge: three (H,W) channels become one (H,W,3) image. Splitting with cv2.extractChannel drops that axis, so that is the setting the round trip needs. |
| array3opt | NPARRAY | Optional third array, appended after the second. | |
| array4opt | NPARRAY | Optional fourth array, appended after the third. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| nparray | NPARRAY | The joined array. Its size on the concat axis is the sum of the inputs'; every other axis is unchanged. |
| length | INT | Size of the result along the concat axis - handy for splitting it back apart with 'CV Take By Index'. |