cv2.CV_32FC
The type code that stops your Sobel filter truncating
- int
If you only ever use one of the eight type-code nodes in bmad4ever's ComfyUI CV pack, make it this one. cv2.CV_32FC produces the float32 type code, and float32 is the answer to the most common silent wrongness in classical CV: derivative filters applied to 8-bit images.
Sobel, Scharr, Laplacian and any filter2D with a kernel that has negative lobes compute values that go below zero. Ask for the output in the input's own depth and cv2 clips or wraps them, and the pack's own tooltip for cv2.Sobel quotes the OpenCV warning verbatim: with 8-bit input, ddepth of the same size "will result in truncated derivatives". You get an edge map that looks almost right and is wrong at every sign change. Ask for CV_32F and it's right.
How the code works
The macro packs depth and channel count into one integer: depth + ((channels − 1) << 3). CV_32F is depth 5, so CV_32FC(1) is 5 - identical to the plain CV_32F constant - and CV_32FC(3) is 21. That equivalence is the practical heart of it: filter ddepth parameters want a depth, and a one-channel float code is exactly that. Multi-channel spellings matter for the dtype parameters that carry a full type (the arithmetic on a 3-channel image, for instance), which is why the node takes a channel count at all.
channels is an INT with a default of 0, which the macro turns into a nonsense negative code - channels − 1 underflows. Set 1 for a filter depth, 3 for a three-channel type.
The output is a plain INT socket named int. To use it, right-click the receiving node's ddepth/dtype widget → Convert widget to input, then wire. The parameters in question are plain integer widgets in this pack - the pack enums the ones with a small closed set of answers, and leaves the rest as numbers - so if you'd rather just type 5, nothing stops you. The README is candid that the ~470 wrappers are auto-generated from cv2's type stubs, uncurated, and exist to expose the function rather than to be convenient.
Where the code gets used
The wrappers whose docs say "see the combinations" are all here: cv2.Sobel, cv2.Scharr, cv2.Laplacian, cv2.boxFilter, cv2.sqrBoxFilter, cv2.filter2D, cv2.sepFilter2D, cv2.reprojectImageTo3D. On the arithmetic side, dtype shows up on cv2.add, cv2.subtract, cv2.multiply, cv2.divide, cv2.addWeighted, cv2.normalize, cv2.reduce, cv2.mulTransposed and cv2.batchDistance - with the same rule of thumb every time: for filters pass a float depth, for arithmetic a code including the channel count if it matters, and remember that -1 is the API's own "same as input" (which the pack's preset dropdowns spell out as "same as input").
Practical uses beyond edge detection: keeping precision through a chain of multiplication and normalisation before you convert back to 8-bit at the end, and giving a difference image somewhere to keep its negatives. Both are the kind of thing the deterministic pixel layer asks you to do properly instead of re-generating.
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 and a recent ComfyUI on the V3 node API. That single pinned dependency is the whole install - but keep the contrib wheel winning. All four OpenCV distributions share one site-packages/cv2, so a later pip install opencv-python from some other pack strips the contrib submodules and nodes start vanishing with no error explaining why. python -c "import cv2; print(cv2.__file__, cv2.__version__)" tells you which one you have; tools/repair_opencv_contrib.py --check then --apply puts it back.
Common issues and troubleshooting
The output is negative. Left channels at 0. Set 1.
Can't connect the output. Convert the destination widget into an input first; a link can't be dropped onto a widget.
Float32 everywhere and now everything is slow / huge. Real cost: 4 bytes a pixel per channel instead of 1. The standard discipline is to convert up for the maths that needs it and back down (cv2.convertScaleAbs is the usual 32F → 8U step, and this pack has it) before the image hits anything generative.
Expecting a conversion. This is a code, not an operation. CV Cast Array is the node that actually changes an array's dtype.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| channels | INT | 0-2147483648–2147483647 | - - - |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| int | INT | — |