cv2.normalize
Two different nodes wearing one name
- src
- mask
- result
cv2.normalize is two operations in a trenchcoat, and which one you get is decided entirely by norm_type. Get that wrong and you'll spend twenty minutes wondering why your image looks almost the same.
The range form (NORM_MINMAX) is the one beginners want: a linear rescale so the array's minimum maps to alpha and its maximum to beta. alpha = 0, beta = 255 stretches a float score map into something displayable; alpha = 0, beta = 1 squashes any range into ComfyUI's float convention. The norm form (NORM_L1 / NORM_L2 / NORM_INF) divides the whole array by its norm and scales by alpha, so the result has norm alpha - the max value lands wherever it lands. Same node, wildly different results.
Note the default: norm_type ships as NORM_L2. People who came for a min-max stretch and left it alone get a subtly rescaled image instead. Set it explicitly.
Where it earns its place
The real job is making numbers into something a human or another node can consume. A distance transform or a Wiener filter result is a float field with arbitrary range - cv2.normalize is how you get it into 0–255 for a preview, and the pack's own Wiener-filter subgraph wires exactly that (0, 255, NORM_MINMAX). The other job is range discipline for masks. ComfyUI masks are 0–1 floats; a mask that arrives with values up to 255 is not "stronger", it's out of contract, and any consumer treating >0 as "on" will read it as a solid block. alpha = 0, beta = 1 is the fix.
alpha and beta carry OpenCV's exact meanings, and the author's tooltips say so: alpha is "the norm value to normalize to or the lower range boundary in case of the range normalization"; beta is the upper range boundary and "is not used for the norm normalization". So in the range form you set both; in the norm form beta is decoration.
Inputs, output, and the caveats
src is the single required input and decides the output's format - IMAGE in, IMAGE out; MASK in, MASK out; NPARRAY stays NPARRAY. The optional mask participates in the computation (it restricts which pixels define the range or the norm), same size as src, CV_8U/CV_8S/CV_Bool. dtype defaults to "same as input"; switch it to CV_32F when an 8-bit result would clip the stretched values.
Two honest warnings. A min-max stretch is not colour correction. It's one global linear map applied across every channel of the array, so a per-channel or perceptual stretch is not what you're getting - if the goal is "make this image look right", a gamma curve or a statistics-based colour match is the better tool, and the KB's post-processing doc makes a point of reaching for the deterministic primitive that matches the job. And a flat array has nothing to stretch: if min equals max (an all-black mask, a constant field), you're asking a range normalizer to normalize a range that doesn't exist, so don't build on the result.
One more: normalizing a constant-shaped array to a fixed norm (L2 to alpha = 1) is a genuine technique - that's how you make vectors comparable for matching without caring about their original scale. Just be sure that's what you meant.
Install
ComfyUI Manager → search ComfyUI CV → install → restart, or:
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 recent ComfyUI on the V3 node API. Core cv2; no contrib submodule, no models. The pack's CV Array -> Mask bridge min-max normalizes floats on the way in, so a float array and the mask socket agree by default - one less conversion to get wrong.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| src | COMFY_MATCHTYPE_V3 | input array. The image output(s) echo this input's format. 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. | |
| alphaopt | FLOAT | 1.0000-1e+38–1e+38 | norm value to normalize to or the lower range boundary in case of the range normalization. Preset to the OpenCV default (1.0). |
| betaopt | FLOAT | 0.0000-1e+38–1e+38 | upper range boundary in case of the range normalization; it is not used for the norm normalization. Preset to the OpenCV default (0.0). |
| norm_typeopt | COMBO | NORM_L2 | normalization type (see cv::NormTypes). |
| dtypeopt | COMBO | same as input | when negative, the output array has the same type as src; otherwise, it has the same number of channels as src and the depth =CV_MAT_DEPTH(dtype). |
| maskopt | NPARRAY,IMAGE,MASK | optional operation mask of type CV_8U, CV_8S or CV_Bool. 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. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| result | COMFY_MATCHTYPE_V3 | Echoes the 'src' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY. |