CV Detect MSER Regions
Threshold-free region proposals that survive bad lighting
- image
- regions
- mask
- boxes
- areas
- count
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 withCV Draw Contoursor measure withCV 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
deltaand tightenmax_area. Both are in the tooltips for a reason. - Everything is one giant region plus specks. Raise
min_area, lowermax_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 Componentand 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.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | NPARRAY,IMAGE | Image 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. | |
| delta | INT | 51–100 | Threshold step over which a region's area must stay stable. LARGER = fewer, more solidly stable regions; smaller = many more, including near-duplicates. |
| min_area | INT | 601–10000000 | Smallest region area in pixels - raise it to drop noise specks. |
| max_area | INT | 144001–10000000 | Largest region area in pixels; caps the whole-image region that is otherwise always 'stable'. |
| max_variation | FLOAT | 0.250–1 | Prune a region whose area varies more than this relative amount over 'delta'. Lower = stricter. |
| polarity | COMBO | both (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_diversityopt | FLOAT | 0.200–1 | Prune a region that is too similar in area to its parent - this is what suppresses nested near-duplicates. |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| regions | CV_CONTOURS | One 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'. |
| mask | NPARRAY | uint8 0/255 union of the EXACT region pixels (not the hulls) - the lossless form of the result. |
| boxes | NPARRAY | Nx4 int32 (x, y, w, h) bounding boxes, one per region. |
| areas | NPARRAY | (N,) float32 exact pixel count of each region. |
| count | INT | How many regions were found; 0 is valid, not an error. |