CV Array To Numbers
The bridge that turns one array into fifty graph executions
- nparray
- value
- count
ComfyUI has a second kind of data flow that surprises people the first time they meet it: a socket can carry a list, and everything downstream then executes once per value. That's how Inspire foreach loops iterate over detections, and it's how Basic Data Handling's whole sort/filter/min/max surface works. CV Array To Numbers is the door from array-land into that world: it takes the values in a numpy array and emits them as a ComfyUI list of FLOATs.
Why you'd reach for it
- Per-detection work. A table of N detections feeds a list of N floats, and a downstream chain runs N times - crop the Nth region, process it, save it. That's the loop construct ComfyUI gives you.
- Sort, filter, aggregate. Hand the list to Basic Data Handling's convert node and you get the whole toolkit: max, min, sum, sort, and the ability to pick one and feed it back as a scalar.
- A score column as a gate. Column 4 of a detection table is usually the score. Emit it as numbers, threshold it in the helper pack, and you've built confidence filtering without a dedicated node for it.
The inputs that matter
nparray- the array to read.NPARRAYonly.column- for a 2-D array, which column to emit.-1means every value, row by row, which is the default. Set it to a specific column and you get just that column - the mechanism above.max_items(optional) - a safety cap, default 1024, and it's the most important number in the node.
Outputs: value - one FLOAT per value, in order, marked as a list, so the socket fans out as an iterable. count - how many were actually emitted, after the cap.
The thing to understand before you use it
Every value is a separate execution of everything downstream. The pack's own tooltip says it plainly: a whole image here would run the rest of the graph a million times. That's not a performance warning, it's a design contract - and it's why max_items exists, why its default is a modest 1024, and why you should treat this node as "emit a few numbers and loop over them" rather than "dump an array into the graph".
Rule of thumb: this node belongs on a detection table with tens of rows. If you're thinking in thousands, you want vectorised array operations instead - the pack's wrappers do arithmetic across whole arrays in one execution, which is a couple of orders of magnitude cheaper than looping.
Two mismatches that will bite
- INT and FLOAT sockets don't auto-coerce. This node emits floats by definition. A consumer that wants an integer index needs Basic Data Handling's to INT conversion in between, and it will not warn you beyond refusing to connect.
- Rows are not values. If you wanted to iterate over whole rows as arrays - "each detection as a 4-element array" - this is the wrong node.
CV Unstack Batchdoes that job, and the difference matters as soon as the downstream consumer wants more than one number per item.
Install
ComfyUI Manager → ComfyUI CV, or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
restart, done. Dependencies are opencv-contrib-python-headless~=5.0.0.93, numpy and torch, with Python 3.12+ and a ComfyUI on the V3 node API. Note that the interesting half of this node's life happens in other packs - the README lists ComfyUI-Inspire-Pack, ComfyUI-Custom-Scripts and Basic Data Handling as dependencies of the pack's own example workflows, and those are exactly the consumers you'd wire this into. Install them via Manager if a downloaded workflow opens red.
Traps
max_itemssilently truncates. Thecountoutput tells you the truth; if it equals your cap, you lost data. Raise it deliberately, knowing what per-item executions cost you.column = -1on a big 2-D array is a flood. Row-major order, every value, one execution each. On anything image-sized, that's the mistake the cap was designed to prevent - don't defeat it.- Order is row-major. The Nth value is the Nth cell, so a list index only maps back to a detection if your table is in detection order.
- A list output changes the identity of the node it feeds. Downstream nodes that expected a scalar will now run N times and their outputs accumulate. If you see a graph suddenly producing an unexpected batch, look upstream for the node that turned a value into a list - it's usually this one.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| nparray | NPARRAY | Array to read. A 2-D array is read row by row unless 'column' picks one column out of it. | |
| column | INT | -1-1–4095 | For a 2-D array: which column to emit (-1 = every value, row by row). Column 4 of a detection table is its score, so this is how a score column reaches the list nodes. |
| max_itemsopt | INT | 10241–100000 | Safety cap on the number of values emitted. Each one is a separate downstream execution, so a whole image here would run the rest of the graph a million times. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| value | FLOAT | One FLOAT per value, in order. Cast with 'Basic data handling: to INT' if a consumer needs an integer - INT and FLOAT sockets do not auto-coerce. |
| count | INT | How many values were emitted (after the cap). |