Nodes/ComfyUI CV/CV Random Seed
ComfyUI Node

CV Random Seed

The seed node that has to sit on a wire

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
CV Random Seed
  • value
  • value
◄seed0►

Here's a node whose output is completely uninteresting - it passes its input through untouched - and which is nonetheless not redundant. It exists because of an execution-order fact that bites everyone who builds a randomised CV pipeline: ComfyUI decides what runs when by following the links.

If you want cv2.kmeans's initial centers, or a RANSAC homography, or cv2.randn to give the same answer twice, you need cv2.setRNGSeed() to have run before them. cv2.setRNGSeed returns void, so the pack's registry generator drops it - it isn't in the ~470 auto-generated cv2.* wrappers. Hence a curated node with a trick: it seeds the global RNG, then hands the value it was given straight back out. The value is the ordering constraint. A seed node feeding nothing could legally run after the node it was meant to seed, and then you'd be debugging an unreproducible pipeline you thought you'd pinned.

What you actually set

  • value - a wildcard (*) input, passed through untouched. Not copied, even; the tooltip says so. Route an existing wire through it: whatever already feeds the randomised node is the natural candidate. Type doesn't matter - IMAGE, MASK, NPARRAY, CV_CONTOURS, MODEL, STRING all pass through, which is what lets you insert this node wherever the wire happens to be rather than being forced to find an array to sit on.
  • seed - INT, 0 to 2147483647.

One output, value, unchanged. Wire it into the input you interrupted.

The caveat that matters

The seed widget on a KSampler and this node are not the same animal, and conflating them is the mistake. A KSampler seed feeds one sampler. CV Set RNG Seed seeds cv2's single global RNG - one generator shared by every cv2 call in the process. So the same seed only reproduces the same result if the same sequence of cv2 draws happens in between. The tooltip says it plainly: "the result also depends on what other cv2 nodes drew from it in between."

Practically: put this node immediately before the randomised node, on a wire that node consumes, and don't expect reproducibility across a graph you've edited. Two extra CV Detect Blobs nodes upstream will change what the RNG is pointing at, and your "deterministic" pipeline quietly isn't.

What it's for

K-means colour clustering, randu/randn fills, RANSAC-based homography and PnP estimation, and the ML nodes. It's also the honest answer to "why does my CV pipeline give a different answer every run" - which is a genuinely common complaint about anything RANSAC-shaped, and the reason this node exists rather than being an afterthought.

Note the interaction with ComfyUI's own caching: because this node's inputs (the seed and the wildcard) don't change between runs, the node itself caches, and cv2's global RNG state does not reset - so on a cached re-run, the downstream node may not execute at all anyway. That's normal graph behaviour, not a bug, but it's why pinning a CV result and pinning a diffusion result feel different.

Install

ComfyUI Manager → ComfyUI CV → install → restart. Or by hand:

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, recent ComfyUI on the V3 node API. No models involved.

Common issues

  • Same seed, different result. Something else drew from the shared cv2 RNG first, or the node isn't on a wire that the randomised node depends on. Both are covered above; check the graph before the seed.
  • You can't find it by searching "seed". It's registered as a class called CV_SetRNGSeed but displays as CV Random Seed, under image/CV/low-level. Both names are in play in the wild.
  • The input socket won't accept your wire. It should - the socket is *. If a node's output refuses to connect, the problem is on the other end.
  • Contrib-backed nodes vanished. A plain OpenCV wheel overwrite. tools/repair_opencv_contrib.py --check, then --apply.
Categoryimage/CV/low-level

Inputs (2)

NameTypeDefaultDescription
value*Any value, passed through untouched (not even copied) - it is here only to force this node to run BEFORE the one you are seeding. Route a wire that already feeds the randomised node through here; the type does not matter.
seedINT00–2147483647Any value; the same seed reproduces the same sequence. Note this is cv2's ONE global RNG, so the result also depends on what other cv2 nodes drew from it in between.

Outputs (1)

NameTypeDescription
value*The input value, unchanged.