cv2.getStructuringElement
The kernel factory every morphology graph needs
- ksize
- anchor
- nparray
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 Dataon 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 installingopencv-pythonoveropencv-contrib-pythonempties the contrib submodules and some of this pack's nodes disappear from the menu.tools/repair_opencv_contrib.py --checkreports it;--applyrepairs 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 Arrayare the bridges.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| shape | COMBO | MORPH_ELLIPSE | Element shape that could be one of #MorphShapes |
| ksize | CV_TUPLE | 3,3 | Size 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. |
| anchoropt | CV_TUPLE | -1,-1 | Anchor 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)
| Name | Type | Description |
|---|---|---|
| nparray | NPARRAY | — |