cv2.CV_16UC
The type code for depth maps and stereo disparity
- int
cv2.CV_16UC builds the OpenCV type code for an unsigned 16-bit array. In the ComfyUI CV pack it's the node cv2.CV_16UC: one INT input named channels, one INT output named int, wrapping the CV_16UC(channels) macro. No image goes in, no image comes out - it produces the single integer that other cv2 wrappers want when they ask for a dtype or ddepth.
That sounds like trivia until you're in stereo or depth territory, where 16-bit unsigned is the storage convention. A stereo disparity map is classically written as CV_16U with the disparity scaled by 16 (or 256, in the newer half-pixel convention) so you keep fractional precision in an integer format. A depth map in millimetres is CV_16U too, because 0–65535 covers 65 metres at 1 mm resolution and the file is half the size of a float32 version - which is why 16-bit PNG depth maps are everywhere in the CV world, and why every depth pipeline in this ecosystem is full of nodes converting between a float tensor and a 16U file.
How the code works
The macro packs depth and channel count: CV_16U is depth 2, and every additional channel adds 8, so CV_16UC(1) is the plain 16-bit unsigned depth code and CV_16UC(3) gets you a three-channel version (a 16-bit-per-channel colour image, legal but rare - that's what a 16-bit-per-channel TIFF carries). You'll mostly pass 1.
The channels widget defaults to 0, which is a trap: the macro computes channels − 1, so 0 yields a nonsense negative code that no cv2 function will accept. Set 1.
The output is a plain INT. Since ComfyUI only lets you wire into inputs, the receiving node's widget has to be converted first - right-click it → Convert widget to input - and then the code can arrive over a link. This is also the point where these code-builder nodes are most honestly assessed: typing 2 into a ddepth field is easier than building it, and the pack's own philosophy admits it. The README states that the ~470 wrappers are auto-generated from cv2's type stubs and uncurated - every top-level function becomes a node, useful or not.
Where 16U meets ComfyUI's data model
Nowhere pleasant, and it's worth saying plainly. A ComfyUI IMAGE is a 3-channel float32 tensor in 0–1; a MASK is a single-channel float. A CV_16U array holding millimetres or scaled disparity fits neither, so it lives in NPARRAY space: produced by a cv2 wrapper, inspected with Inspect CV Data, manipulated with other cv2 nodes, and converted to something visible only at the end (CV Array → Image for a normalised preview, or the pack's depth-specific nodes if you're on the stereo path).
One more pack-specific detail worth knowing before you plan a file-based round trip: cv2.imread and cv2.imwrite are deliberately hidden from this pack - the author blacklists every cv2 function that takes a host filesystem path, so images enter through Load Image and never through a node-supplied path. cv2.imdecode survives because it works on an in-memory buffer. So a 16U depth PNG can be loaded, but not by pointing a wrapper node at it.
Installing it
Manager → search the pack title (ComfyUI CV) → install → restart. Manual:
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, a ComfyUI with the V3 node API, and the contrib wheel. Note the headless part is not a limitation for this pack - no node in it uses a cv2 window - but a non-contrib wheel installed on top will strip the contrib submodules out of the shared site-packages/cv2 and take nodes with it (tools/repair_opencv_contrib.py --check/--apply).
Common issues and troubleshooting
Negative or absurd output value. channels is 0. The macro subtracts one from it internally; give it 1.
The value won't connect to a widget. Convert the widget to an input first. A link dropped on a plain widget is ignored.
Your 16U data looks black in a preview. 16-bit values only fill the top of the 8-bit display range once scaled - normalise before previewing rather than assuming the array is empty. Preview CV Array's normalize mode is there for exactly this.
You wanted to save the 16-bit result to disk. The pack's path-taking functions are hidden on purpose. Route it through the array-to-image bridge and core Save Image, or add your own node - just don't expect to find cv2.imwrite in the node list.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| channels | INT | 0-2147483648–2147483647 | - - - |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| int | INT | — |