Nodes/ComfyUI-HappNodeSet/Hole Counter (Robust)
ComfyUI Node

Hole Counter (Robust)

How many holes are in this part? Now with annotations so you can argue with the answer

By mikemojen·Created 8 months ago·Updated 3 months ago· 0
Hole Counter (Robust)
  • image
  • output_image
  • hole_count
  • hole_info
binary_threshold128
min_hole_area50
max_hole_area_pct0.40
morph_close_size5
morph_dilate_size0
dedup_radius15
invert_imagefalse
use_adaptive_thresholdfalse
adaptive_block_size51
adaptive_c10
annotate_imagetrue
show_debug_binaryfalse

The "Robust" in the display name is doing real work. Hole Counter counts the internal holes in a black-and-white cutting diagram - and it's built to survive the three things that wreck naive hole counters: broken outlines, specks of noise, and scans with uneven lighting. If you're quoting a job, verifying a CAD export against a drawing, or just need to know "is it 48 holes or 49?", this is the node, and it annotates the image so you can see exactly which blobs it counted.

How it works

It shares the pack's laser-path detection machinery with LaserPathTracer: binarize at binary_threshold (default 128), run morphological closing with morph_close_size (default 5) to bridge gaps in hole outlines, dilate with morph_dilate_size (0 = off) to thicken faint strokes, filter by area (min_hole_area default 50 px²; max_hole_area_pct default 0.4 of the external boundary), and merge near-duplicates within dedup_radius (default 15 px). invert_image flips polarity, and use_adaptive_threshold (with adaptive_block_size and adaptive_c) rescues noisy or uneven scans where a fixed threshold fails.

Two outputs-related toggles: annotate_image (default on) draws numbered markers on the detected holes, and show_debug_binary (default off) swaps the output to the raw binarized/debug view instead - invaluable when you're trying to figure out why it sees what it sees.

What comes out

  • output_image (IMAGE) - the annotated drawing, holes numbered.
  • hole_count (INT) - the headline number.
  • hole_info (STRING) - a text list: Holes detected: N followed by each hole's rank and (x, y) center coordinates, sorted by position. Wire it to Show Text for a printable count sheet.

Where it fits

The workflow is Load Image → Extract Black → HoleCounter → Show Text. It composes with LaserPathTracer (same detection core, so the features it counts are the features the tracer will route) and ContourGapCloser (run it first if outlines are broken, since closing heals them before detection). For a QC pass on a drawing, this is the node that turns "I think it's forty-something" into "48, and here are their coordinates."

Install

Part of ComfyUI-HappNodeSet (mikemojen). ComfyUI Manager: search HappNodeSet. Manual:

cd ComfyUI/custom_nodes
git clone https://github.com/mikemojen/ComfyUI-HappNodeSet.git
pip install -r ComfyUI-HappNodeSet/requirements.txt

Restart ComfyUI. OpenCV + numpy; pack-standard deps only.

Common issues

The classic failure is double-counting: a single hole with a broken outline gets detected as two arc-shaped features before closing heals it - so if the count looks high, raise morph_close_size or dedup_radius. Missing holes usually mean min_hole_area is too high or the outline never closed. And max_hole_area_pct is your guard against counting the outer boundary or large shapes as "holes" - if the count includes one giant thing, the boundary leaked through and this setting needs to come down. Read the annotation output, not just the integer; the annotations exist to be checked.

CategoryLaser/Path

Inputs (13)

NameTypeDefaultDescription
imageIMAGE
binary_thresholdINT1280–255
min_hole_areaINT501–50000
max_hole_area_pctFLOAT0.400.01–0.99
morph_close_sizeINT50–31
morph_dilate_sizeINT00–15
dedup_radiusINT150–100
invert_imageBOOLEANfalse
use_adaptive_thresholdBOOLEANfalse
adaptive_block_sizeINT513–201
adaptive_cINT10-30–60
annotate_imageBOOLEANtrue
show_debug_binaryBOOLEANfalse

Outputs (3)

NameTypeDescription
output_imageIMAGE
hole_countINT
hole_infoSTRING