cv2.pow
Cv2.pow is your gamma curve — and the uint8 clipping that comes with it
- src
- nparray
If you have ever nudged a "gamma" slider and wondered what it actually does, this node is the honest version of it: every pixel goes through output = input ^ power. That's it. No model, no seed lottery, milliseconds. The KB's whole post-processing argument is that this layer is deterministic and you should reach for it before spending a diffusion pass - a gamma curve is a gamma curve, and there is exactly one node in this pack that exposes it directly.
What it does and where it fits
cv2.pow is a raw wrapper of the OpenCV function of the same name. Raise-to-a-power is the correct tool for three things: lifting shadows without washing out white (power below 1), crushing midtones (power above 1), and undoing a display gamma when you are doing math in linear space. It's the power-curve operation that post-processing.md contrasts with additive brightness - brightness just adds a constant and clips highlights, a power curve pivots around white instead.
The catch is entirely about data type, and it is the reason people bounce off this node.
The mechanism, and the trap
ComfyUI hands you a float image in 0–1. The wrapper converts an IMAGE link to uint8 BGR before calling cv2, so by the time pow runs your pixels are 0–255 integers in an 8-bit container, and the result is saturated at 255. Square a uint8 image (power = 2) and everything from 16 upward lands on 255 - you don't get a darker image, you get a white rectangle. Same in reverse for anything that would go negative.
So: for a gentle lift, power around 0.8–0.9 on a uint8 image is about as far as you can push before the curve visibly bites. If you want a real tone curve, do the math in float. Wire your image through Image → CV Array with dtype set to float32 (0-1), run cv2.pow on that NPARRAY, and bring it back with CV Array → Image.
Two more things worth knowing before you hit Run:
powerdefaults to 0, andx ^ 0 = 1, i.e. solid white. Type a value. (0.4545 is 1/2.2, the standard display-gamma exponent; 0.5 is a plain square root and a good first experiment.)- The output is NPARRAY, not IMAGE. Unlike the type-preserving filters in this pack,
powdoesn't echo its input's format, so you won't see anything in a preview node until you convert back with CV Array → Image.
Inputs and outputs that matter
There are only two inputs. src takes a ComfyUI IMAGE or MASK directly, or an NPARRAY - an IMAGE is unwrapped to frame 0 unless the function is batch-safe, and pow is in the pack's per-frame batch set, so a whole IMAGE batch of matching size is processed frame by frame and handed back batched. power is the exponent.
Out comes a single nparray socket. Into CV Array → Image for viewing, into CV Array → Mask if you were treating it as a mask, or into any other NPARRAY node for further math.
Installing it
The pack is ComfyUI CV by bmad4ever - about 470 auto-generated cv2.* wrappers (this is one) plus a few hundred hand-written nodes. Install through ComfyUI Manager by searching comfyui_cv, or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
Then restart ComfyUI. The one real dependency is the contrib OpenCV wheel, and it is pinned:
pip install "opencv-contrib-python-headless~=5.0.0.93"
The pack requires Python ≥ 3.12 and a recent ComfyUI built on the V3 node API. It is GPL-3.0, forked from geroldmeisinger's opencv-comfyui, and the author states plainly that raw wrappers are uncurated and that the code was written with heavy LLM assistance - treat the values here as "OpenCV, exposed", not "blessed".
Common issues
Everything is white / black. Almost always the uint8 saturation above, or power left at 0. Check power first, then try the float path.
The contrib submodules vanished. Installing a non-contrib wheel (opencv-python) over a contrib one silently empties site-packages/cv2's contrib modules and those nodes disappear from the menu. The pack ships tools/repair_opencv_contrib.py --check / --apply for exactly this.
Dependency roulette. OpenCV 5.x pulls numpy 2.x. If you also run insightface-style packs that pin numpy 1.x, you'll meet the version-conflict wall the ecosystem doc describes - a real, common thing people hit, and the fix is deciding which side of your stack owns numpy rather than letting pip pick.
It's slow? It isn't. If a run crawls, the cost is elsewhere; pow on a 4K frame is noise-level work.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| src | NPARRAY,IMAGE,MASK | input array. Accepts a ComfyUI IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY. Arithmetic ops (add, multiply, etc.) process the full IMAGE batch when both inputs have the same batch size. | |
| power | FLOAT | 0.0000-1e+38–1e+38 | exponent of power. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| nparray | NPARRAY | — |