Nodes/ComfyUI CV/cv2.divide (1/2)
ComfyUI Node

cv2.divide (1/2)

Divide your image by a blur and the lighting disappears

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
cv2.divide (1/2)
  • src1
  • src2
  • result
◄scale1.0000►
◄dtypesame as input►

Division is the least obvious of the arithmetic nodes and the one with the best single trick: divide an image by a blurred copy of itself and the uneven lighting cancels out, leaving the texture. Vignettes, a lamp on one side, a gradient across the frame - all gone, no model, no generation, one node in front of a blur. Flat-fielding, in the old darkroom sense of the word.

What it computes

Per pixel: dst = saturate(src1 * scale / src2). It's the array-by-array overload of cv2.divide, which is why scale is a multiplier rather than a divisor - ramp it up and the result brightens, drop it below 1 and it darkens. Type src1 and src2, both the same size, and you get array division.

This is the node in the pack's Fourier playground, where spectrum math needs a real division step. For day-to-day masking work, the "divide by the local average" flat-field is the reason to learn it.

Inputs and outputs

src1 accepts an IMAGE, MASK or NPARRAY, and also a LATENT. src2 takes the same set. The output is a single result that echoes src1's format - wire a MASK in and you get a MASK back, which is how you build a ratio matte without leaving mask-land. When both inputs are IMAGE batches of the same batch size, the whole batch flows through rather than just frame 0; mismatched batch sizes are the exception the pack guards against.

scale is a float defaulting to 1.0, labelled "scalar factor" in the tooltip. On integer data treat it gently: src1 * scale happens before the division, in the input's integer arithmetic, so a scale of 3 on a uint8 array of 200s is an overflow, not 600.

dtype is the output depth, default "same as input". The tooltip spells out the trap: -1 means "use src2's depth", and for array-by-array division you're only allowed -1 when both inputs already have the same depth. In practice, leave it alone unless you have a reason - if you want float math, convert to float upstream so both sides match.

Where it fits

The classic chain is three nodes: cv2.blur (or a big Gaussian) to make the illumination reference, cv2.divide to remove it, then a contrast pass. It's also the arithmetic half of the pack's CV Photometric Align (Gain/Bias) idea - that node fits src*gain+bias ≈ ref for colour matching between two frames; divide gets you the multiplicative half of the same story.

Nobody should be doing colour correction with an img2img pass, and the KB's docs/knowledge/post-processing.md makes that argument at length. A ratio is deterministic, instant, and identical every run.

Installing comfyui_cv

One node from bmad4ever/comfyui_cv - ~470 auto-generated raw cv2.* wrappers plus curated nodes, a GPL-3.0 fork of Gerold Meisinger's opencv-comfyui, curated against OpenCV 5.0.0.93. Manager: search ComfyUI CV and install. Or:

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv

Restart after installing. Requires Python ≥ 3.12 and a recent ComfyUI built on the V3 node API. The only dependency is opencv-contrib-python-headless~=5.0.0.93; a non-contrib opencv-python installed over it empties the contrib submodules and takes contrib nodes with it (tools/repair_opencv_contrib.py --check finds that, --apply fixes it).

Common issues

Black patches. Division by zero returns 0 in the array path, silently. Any black pixel in src2 becomes a black pixel in the result - which is also why flat-fielding a crushed-black image gives you a spotted mess. Lift the divisor slightly (a tiny constant add upstream) or mask those pixels.

Everything is white / clipped at 255. You're dividing by small numbers in uint8. Do the math in float: convert both sides to float, divide, then normalize.

"(-215) ... sizes do not match". The two arrays must line up exactly. Add or subtract a blur first and check that nothing cropped or resized one side.

File size, not meaning. If you wanted a difference (a subtraction, a delta), cv2.subtract and cv2.absdiff are the nodes you're looking for; divide is for ratios. The scalar-over-array variant is a separate node, cv2.divide (2/2).

Categoryimage/CV/low-level/cv2 D

Inputs (4)

NameTypeDefaultDescription
src1COMFY_MATCHTYPE_V3first input array. The image output(s) echo this input's format. A LATENT link is processed in latent space: frame 0 becomes a float32 [H,W,C] array (any channel count), values untouched. Arithmetic ops (add, multiply, etc.) also accept a full LATENT batch ({samples: [B,C,H,W]}) — the whole batch flows through when both inputs have the same batch size. 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.
src2NPARRAY,IMAGE,MASK,LATENTsecond input array of the same size and type as src1. A LATENT link is processed in latent space: frame 0 becomes a float32 [H,W,C] array (any channel count), values untouched. Arithmetic ops (add, multiply, etc.) also accept a full LATENT batch ({samples: [B,C,H,W]}) — the whole batch flows through when both inputs have the same batch size. 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.
scaleoptFLOAT1.0000-1e+38–1e+38scalar factor. Preset to the OpenCV default (1.0).
dtypeoptCOMBOsame as inputoptional depth of the output array; if -1, dst will have depth src2.depth(), but in case of an array-by-array division, you can only pass -1 when src1.depth()==src2.depth().

Outputs (1)

NameTypeDescription
resultCOMFY_MATCHTYPE_V3Echoes the 'src1' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY.