Nodes/ComfyUI CV/cv2.ximgproc.contourSampling
ComfyUI Node

cv2.ximgproc.contourSampling

Turn an edge map into a fixed number of points

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
cv2.ximgproc.contourSampling
  • src
  • nparray
◄nbElt0►

Here's a problem that comes up the moment you try to compare shapes: contours have no fixed length. One outline is 412 points, the next is 87, and every shape descriptor, classifier and distance function downstream wants a vector of fixed size. cv2.ximgproc.contourSampling walks the contours in a binary map and resamples them down to a requested number of points, roughly evenly distributed along the curve. Variable-length geometry in, fixed-length point set out.

The classic pipeline it slots into is shape classification: Canny edge map → sample to N points → compare against templates (cv2.matchShapes, or a Fourier descriptor) → decide. The pack ships all the pieces: cv2.Canny, this node, cv2.matchShapes, and CV Quality-style scoring to check whether a match is actually close.

Inputs and output

  • src - the contour/edge image. An IMAGE, MASK or NPARRAY. Worth being deliberate here: this wants a single-channel binary-ish map, so the safest wire is a MASK (which arrives single-channel) or an array from Image → CV Array set to gray - an IMAGE reaching cv2 as 3-channel BGR isn't what the function expects, and this wrapper doesn't auto-grayscale for you.
  • nbElt - how many points you want. This is your fixed vector length, so pick it to match whatever consumes it: 100 is a reasonable default for a shape signature, more if the contours are gnarly.

One NPARRAY comes out - the sampled points, which is the pack's general-purpose data socket. From there, CV Points To Contour converts it back into a contour if a cv2 function expects one, CV Points To Polar switches to (r, θ) about an origin, or CV Scale Points re-normalises them for scale-invariant comparison. Since the whole point is comparing shapes, the normalisation step is often the one that actually makes the comparison work.

Why a fixed point count fixes things

A shape descriptor that takes N points lets you do arithmetic: average two shapes, interpolate between them, feed them to a classifier, compute a distance. The pack leans into that with its own example exercises - the HOG shape classifier examples in the repo's workflows/ folder are literally "sample contours, extract features, predict a class" - and CV Deep Features / CV Predict Classifier are the end of that road if you want to train something.

There's a subtlety worth knowing before you trust the sampling: resampling a curve to equal point spacing is not the same as equal arc length spacing, and cv2's sampling is approximate. For shape matching that's usually fine - you're comparing like with like, since both shapes went through the same sampler. For measurement (perimeter, curvature) it isn't; use cv2.arcLength and analytic geometry instead.

Installing it

Contrib module, shipped in ComfyUI CV. Manager → search ComfyUI CV, 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 and a recent, V3-API ComfyUI.

What goes wrong

  • nbElt left at 0 - the default is zero points, so nothing useful comes out. This is one of those parameters with no useful OpenCV default that the wrapper still has to show you.
  • Empty output. There were no contours in the input - usually because the edge map was inverted, or the threshold threw everything away. Preview the Canny result before feeding it in.
  • Fewer points than you asked for. Sampling is bounded by the contour's own pixel count; a tiny contour can't yield 500 distinct samples.
  • Multi-channel input. Give it a single-channel map. If you're unsure which you have, Inspect CV Data reports the shape.
  • ximgproc missing from the menu. Contrib-only submodule, and all four opencv-python* distributions share one site-packages/cv2 - a non-contrib wheel leaves the submodules as empty stubs. tools/repair_opencv_contrib.py --check in the pack repo reports it, --apply repairs it.
Categoryimage/CV/low-level/ximgproc

Inputs (2)

NameTypeDefaultDescription
srcNPARRAY,IMAGE,MASK - - - 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.
nbEltINT0-2147483648–2147483647 - - -

Outputs (1)

NameTypeDescription
nparrayNPARRAY—