ComfyUI Node

cv2.max

Per-pixel maximum, a.k.a. the Lighten blend mode (not the max of your image)

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
cv2.max
  • src1
  • src2
  • result

There is no ambiguity in this node, there's only misreading it. cv2.max compares two arrays pixel by pixel and keeps the larger value at each position. It is not "find the brightest pixel" - that's cv2.minMaxLoc, a different node in the same letter of the alphabet, and mixing the two up is the single most common way people end up confused here.

Once you read it correctly it's a genuinely useful primitive, because per-pixel max is Photoshop's Lighten blend mode. Two names, one operation. It's how you union two masks, keep the brighter of two exposures, or build a bloom/glow pass by maxing an image with a blurred copy of itself.

The sockets

src1 is the format-echoing side: IMAGE, MASK or NPARRAY, and whatever you link in is what you get back - MASK in, MASK out. That echo is what makes mask algebra pleasant. Max two masks and you've unioned them, in the image-space the rest of your graph understands.

src2 accepts NPARRAY, IMAGE/MASK, and LATENT. The pack treats a LATENT as float32 [H,W,C] frame 0 with values untouched, and max is also on the pack's latent-batch list, so a full {samples: [B,C,H,W]} batch can flow through when both inputs have the same batch size. A constant second operand comes from CV Scalar, which is how you clip everything to a ceiling value without building an image full of that number.

There are no optional parameters, and one output that echoes src1. Note the asymmetry: the pack echoes src1's format, so if you want a MASK out, src1 is where the mask goes.

What it's actually for

  • Mask union. The honest one. max(mask_a, mask_b) is OR.
  • Lighten compositing. Keep the brighter pixel of two takes - a free hand-held "HDR" pair merge, and the deterministic cousin of the blur-and-screen bloom people build by hand.
  • Clipping highlights. min(image, ceiling) and max(image, floor) - the pack's cv2.min is the other half, and together they're a levels clamp with no node hunting.
  • Latent experiments. Maxing two latents is crude and unprincipled, but it's legal here and it's a fast way to see whether two samples share structure.

Installing the pack

ComfyUI CV (bmad4ever/comfyui_cv) - search "comfyui_cv" in ComfyUI Manager, or:

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"

Restart ComfyUI. Python ≥ 3.12, a ComfyUI with the V3 node API, one pinned contrib OpenCV wheel, no models. cv2.max is core OpenCV and runs as fast as the memory copy underneath it.

Where people get burned

Size and type must match exactly. OpenCV does no broadcasting. A 1024×1024 against a 1024×1023 is an error, and uint8 against float32 is an error - two IMAGEs from different resolution branches will collide the moment you resize one of them. Wire a resize in and move on.

Batch behaviour is conditional. A whole IMAGE batch is processed only when both inputs have the same batch size; otherwise you get frame 0. So "maxing a batch against a single image" quietly compares frame 0 to frame 0. If you need the same reference against every frame, match the batch sizes first (Image Batch → CV Batch, then back).

Channel counts. A 3-channel BGR image and a 1-channel mask don't combine; one of them has to change first.

Two IMAGE inputs and a MASK output expectation. The echo follows src1. Wire the MASK to src1.

The contrib gap, since it bites every node in this pack: all four opencv-* wheels install into the same site-packages/cv2, so any pack that drops a non-contrib opencv-python over your contrib wheel silently empties the contrib submodules and the contrib-backed nodes stop appearing in the menu. python tools/repair_opencv_contrib.py --check, then --apply if it reports a problem. And take the author's own caveat seriously - the codebase was written with heavy LLM assistance and isn't recommended for production without review.

Categoryimage/CV/low-level/cv2 M

Inputs (2)

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.

Outputs (1)

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