Nodes/ComfyUI CV/CV Detect MSER Regions
ComfyUI Node

CV Detect MSER Regions

Threshold-free region proposals that survive bad lighting

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
CV Detect MSER Regions
  • image
  • regions
  • mask
  • boxes
  • areas
  • count
◄delta5►
◄min_area60►
◄max_area14400►
◄max_variation0.25►
◄polarityboth (dark and bright regions)►
◄min_diversity0.20►

CV Detect MSER Regions finds maximally stable extremal regions: blobs whose area barely changes as you sweep the grayscale threshold across a wide range.

That definition sounds academic until you compare it to the alternative. CV Find Contours on a thresholded image needs you to pick the threshold, and picks exactly one brightness level - so anything darker or brighter than that is invisible. MSER sweeps every threshold at once, in one pass, and keeps the regions that hold their shape across a broad band of them. Regions at different brightness levels all come out together, which is why it survives uneven lighting that kills a single-threshold pipeline.

The classic uses: text and sign detection (letters are extraordinarily stable regions - they're dark or light, they have consistent thickness, they hold their area over a wide threshold range), and generic region proposals to hand to a classifier or a matcher.

How it works, and the one setting that controls everything

As the threshold rises, regions grow, merge, and vanish. MSER tracks the area derivative for each candidate and keeps the ones that flatten out over a step of delta (default 5). Larger delta means fewer, more solidly stable regions; smaller means many more, including near-duplicates. That single knob is the difference between 30 regions and 3000, so tune it first.

The stability test is also what max_variation (0.25) prunes on: a region whose area varies more than that fraction over delta is discarded. Lower is stricter. And min_diversity (0.2) prunes a region that's too similar in area to its parent, which is what suppresses nested near-duplicates.

One structural fact worth knowing before you wire it up: regions may nest and overlap. MSER is not a segmentation - it's a union of exactly stable regions, and a letter inside a sign inside a poster gives you three nested regions. Plan for that with a filter rather than being surprised by it.

Inputs and outputs

  • image - IMAGE, MASK or NPARRAY, grayscaled internally.
  • delta (5) - the stability step.
  • min_area (60) / max_area (14400) - pixel bounds. The max exists for a real reason: the whole image is trivially the most stable region of all, so it has to be excluded.
  • polarity - both (the default) runs the detector twice, once normally and once inverted, so you get dark-on-light and light-on-dark regions. Restrict it only when you know which you want and want half the work.
  • max_variation (0.25), min_diversity (0.2).

Outputs, and they're a nice set:

  • regions - one contour per region, its convex outline (CV_CONTOURS), so draw with CV Draw Contours or measure with CV Shape Moments.
  • mask - uint8 0/255, the union of the exact region pixels, not the hulls. This is the lossless output; the contours are the simplified one.
  • boxes - Nx4 int32 bounding boxes, one per region.
  • areas - exact pixel count per region, ideal for filtering.
  • count.

Zero regions is a valid result.

Install

Part of 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, recent V3-API ComfyUI. MSER is a class rather than a function, which is why the raw wrapper generator can't produce it - the pack's README is honest that class-based APIs need a curated node, and this is one. Keep the contrib wheel in place; sharing one site-packages/cv2 across four OpenCV distributions means any other pack installing plain opencv-python will gut the contrib nodes. tools/repair_opencv_contrib.py --check / --apply.

Common issues

  • Region count explodes. Raise delta and tighten max_area. Both are in the tooltips for a reason.
  • Everything is one giant region plus specks. Raise min_area, lower max_area. The extremes are the useless ends.
  • Nested duplicates make your labelled boxes useless. Raise min_diversity, or sort by area and keep the outermost.
  • It's slow on large frames. MSER is a union-find sweep over every threshold level; on a 4K image, downsample first. Text detection does not need 4K - in fact the region stability is often better at moderate resolution, where stroke thickness is a few pixels rather than thirty.
  • You wanted the shapes filled and separated. This node gives you a union mask. CV Keep Largest Component and the connected-components nodes are the ones that turn that into clean islands.

If your targets are round-ish and light-ish rather than text-like, CV Detect Blobs is the more direct tool - it filters on shape, which this node doesn't. And if what you actually want is semantic regions, this is not a segmentation model; SAM and friends do that job, at a very different cost.

Categoryimage/CV/contours

Inputs (7)

NameTypeDefaultDescription
imageNPARRAY,IMAGEImage to search (converted to grayscale internally). 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.
deltaINT51–100Threshold step over which a region's area must stay stable. LARGER = fewer, more solidly stable regions; smaller = many more, including near-duplicates.
min_areaINT601–10000000Smallest region area in pixels - raise it to drop noise specks.
max_areaINT144001–10000000Largest region area in pixels; caps the whole-image region that is otherwise always 'stable'.
max_variationFLOAT0.250–1Prune a region whose area varies more than this relative amount over 'delta'. Lower = stricter.
polarityCOMBOboth (dark and bright regions)MSER normally runs twice - once on the image and once inverted - so it finds dark-on-light AND light-on-dark regions. Restrict it to the second pass only when you know the polarity and want half the work.
min_diversityoptFLOAT0.200–1Prune a region that is too similar in area to its parent - this is what suppresses nested near-duplicates.

Outputs (5)

NameTypeDescription
regionsCV_CONTOURSOne contour per region (its convex outline) - draw with 'CV Draw Contours' or measure with 'CV Shape Moments'. Convex hulls, so concave detail is in 'mask'.
maskNPARRAYuint8 0/255 union of the EXACT region pixels (not the hulls) - the lossless form of the result.
boxesNPARRAYNx4 int32 (x, y, w, h) bounding boxes, one per region.
areasNPARRAY(N,) float32 exact pixel count of each region.
countINTHow many regions were found; 0 is valid, not an error.