Nodes/ComfyUI CV/cv2.getStructuringElement
ComfyUI Node

cv2.getStructuringElement

The kernel factory every morphology graph needs

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
cv2.getStructuringElement
  • ksize
  • anchor
  • nparray
◄shapeMORPH_ELLIPSE►

Dilate, erode and morphologyEx all want a kernel, and this is the node that builds one. No image goes in; the output is a small uint8 array on the NPARRAY socket, and you wire that array into the kernel input of whatever morphology wrapper you're using. It is the most-used node in this pack's shipped examples - the mask cleanup steps in the optical-flow, watershed, colour-range and QR workflows are all built from one or two of these feeding a cv2.morphologyEx.

The two inputs that matter

shape is a dropdown of OpenCV's MorphShapes, defaulting to MORPH_ELLIPSE - and the default is the right one more often than not:

  • MORPH_ELLIPSE - a filled disc. This is your general-purpose mask cleanup kernel: it doesn't favour the horizontal or vertical direction, so closing gaps in a blob doesn't square off the blob. The pack's workflows use it for "cleanup kernel", "seed kernel", "coarse kernel" and "3x3 kernel" duties, at sizes from 3×3 up to 27×5.
  • MORPH_RECT - a solid rectangle. Reach for it when you do want directional, structural cleanup: the document-perspective example uses a 5×5 rect to tidy text baselines, where a disc would leave the horizontal strokes uneven.
  • MORPH_CROSS - a plus sign. Thin, and good for line work: it thins and connects without fattening a stroke in all directions. It's also the only shape whose appearance actually depends on the anchor - the pack's tooltip says so explicitly, and it's right: for the other two shapes the anchor just shifts the result.

ksize is the kernel size (w, h) as a composite CV_TUPLE. Note it's (w, h) and it doesn't have to be square - (27, 5) shows up in the shipped morphology playground, an oblong kernel for cleaning a mask whose features are long and thin. Author it with CV Tuple (component sockets take INT links) or type the literal in place; being composite, it can't arrive half-connected, which is a feature.

anchor is optional and defaults to (-1, -1), meaning the centre. For a disc or a rectangle you'll want to leave it there; for a cross, shifting the anchor is how you bias which direction the plus extends. Only the cross genuinely cares.

Where the kernel goes

Straight into the kernel input of the cv2 wrappers - cv2.dilate, cv2.erode, cv2.morphologyEx (with its op dropdown for open/close/gradient/top-hat) - and, in practice, into two or three of them at once. Fan-out is the point: one kernel constant, many consumers, no chance of two cleanup steps disagreeing about their size. That's the plumbing pattern worth stealing.

Two calibration habits from the workflows: dilate to grow a mask, erode to shrink it, open (MORPH_OPEN) to remove speckle, close (MORPH_CLOSE) to fill pinholes. And measure your kernel against your image: a 15×15 on a 640×480 frame is a heavy hitter, and the same kernel on a 64-pixel training tile is a black hole. CV Tuple makes the number visible in one place, which is half the battle.

For everyday "fill the holes in this mask" jobs the pack's curated CV Fill Holes and CV Connected Components (Split Mask) may already be what you want - they're hand-written and do more thinking than "convolve with a kernel". This node is the primitive underneath that kind of step, and the one you reach for when you're composing morphology yourself.

Install

pip install "opencv-contrib-python-headless~=5.0.0.93"

ComfyUI Manager → search ComfyUI CV, or:

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

Restart ComfyUI after. Python ≥ 3.12 and a recent ComfyUI on the V3 node API are required, and the pack is curated against OpenCV 5.0.0.93 - explicitly, because the README warns other versions may behave differently.

Gotchas

  • The output is a kernel, not an image. It'll preview as a tiny grey rectangle at best. Inspect CV Data on it tells you the shape and dtype; that's the honest check that a 5×5 came out 5×5 and not 5×1.
  • Non-contrib wheel trap. All four OpenCV PyPI distributions write into the same site-packages/cv2, so installing opencv-python over opencv-contrib-python empties the contrib submodules and some of this pack's nodes disappear from the menu. tools/repair_opencv_contrib.py --check reports it; --apply repairs it.
  • Uncurated wrapper. The pack's README is blunt: the auto-generated cv2.* nodes are raw, the development involved heavy LLM assistance, and updates aren't planned. A three-argument kernel factory is about as safe as that gets, but don't expect the wrapper to validate your choices - an even size on a disc kernel, or an anchor outside the kernel, is your problem, not its.
  • Mask vs image. Morphology on a MASK is single-channel and works on 0/255; on an IMAGE it processes each channel independently, which is usually not what you want for mask cleanup. Keep the mask lane clean: CV Array → Mask / Mask → CV Array are the bridges.
Categoryimage/CV/low-level/cv2 G

Inputs (3)

NameTypeDefaultDescription
shapeCOMBOMORPH_ELLIPSEElement shape that could be one of #MorphShapes
ksizeCV_TUPLE3,3Size of the structuring element. One value with 2 components (x, y) - it travels as a whole, so it cannot arrive half-connected. Wire it from 'CV Tuple' or type the components in place.
anchoroptCV_TUPLE-1,-1Anchor position within the element. The default value $(-1, -1)$ means that the anchor is at the center. Note that only the shape of a cross-shaped element depends on the anchor position. In other cases the anchor just regulates how much the result of the morphological operation is shifted. One value with 2 components (x, y) - it travels as a whole, so it cannot arrive half-connected. Wire it from 'CV Tuple' or type the components in place.

Outputs (1)

NameTypeDescription
nparrayNPARRAY—