GROUT Segmentation
Spot grout lines in mosaic photos without hand-painting a single mask
- image
- probability_heatmap
- binary_mask
- mask
ComfyUI-GROUT is a small research pack built for one very specific job: finding the grout lines in mosaic and tile imagery. GROUTSegmentation is the actual workhorse - the other two nodes in the pack are just its heatmap and mask accessories. If you've ever tried to select thin dark seams between tiles by hand, you already know why this exists. That's the kind of fiddly, repetitive masking work that eats an afternoon, and a model trained for exactly that beats a lasso tool every single time.
The model underneath is GROUT ("Geometric Reasoning Over Unstructured Tessellations"), a single-class segmentation model from Radoslav Lovecky and colleagues at Arperon / the Institute of Advanced Technologies in Slovakia. It's academic, MIT-licensed, has a paper on Zenodo and the weights on HuggingFace. The node wraps a segmentation-models-pytorch U-Net with an efficientnet-b3 encoder, runs your image through it, and applies a sigmoid so every pixel comes back as a probability between 0 and 1. Then it hands you that probability map, a hard thresholded version, and a proper ComfyUI mask.
Keep expectations honest, though. This is a specialized model, not a general-purpose segmenter. It knows grout lines and the kind of thin geometric seams the "zeroshot" in the checkpoint name hints it generalizes to. Feed it a portrait and you'll get whatever the model thinks is grout, which will not be useful. Reach for it on mosaic, tile, brick, or tessellated imagery.
Here's what you actually touch:
- image - the mosaic image, an IMAGE tensor straight from Load Image.
- device -
cudaorcpu. Pick cuda if you've got an NVIDIA GPU (which you almost certainly do if you're running ComfyUI with one). The node falls back to CPU if CUDA isn't available, but that's slow. - mode -
scaleresizes to 512×512, runs inference, and resizes the probability map back to full resolution.sliding_windowwalks patches across large images so fine detail survives; it's the one to use on anything bigger than roughly a megapixel. - threshold - 0.5 default, 0–1 slider. Everything above it counts as grout in the binary output.
- patch_size / overlap - only matter in sliding_window mode. Patch size defaults to 512 (128–1024), overlap 64. Bigger overlap smooths the seams between patches but costs time.
- model_path (optional) - leave empty and the node auto-downloads
grout_b3_zeroshot_v1.pthfrom HuggingFace toComfyUI/models/grout/on first run. Supply a path only if you already have the weights.
Three outputs: probability_heatmap (a grayscale IMAGE where bright = confident grout), binary_mask (the thresholded IMAGE), and mask (a real ComfyUI MASK, ready to wire into compositing, inpainting, or any image-manipulation node).
Install is standard. ComfyUI Manager → search "GROUT" → install, or:
cd ComfyUI/custom_nodes
git clone https://github.com/advancedtech-sk/ComfyUI-GROUT.git
cd ComfyUI-GROUT
pip install -r requirements.txt
Then restart ComfyUI. The requirements (torch, segmentation-models-pytorch, huggingface_hub, numpy, Pillow, matplotlib) install into your existing ComfyUI environment - same shared-Python gotcha as every custom node, so if you're running a hundred nodes and something conflicts, that's the usual culprit, not this pack specifically.
Troubleshooting worth knowing:
- First run downloads the weights. The node prints "Downloading model from HuggingFace..." and can't run without that file, so if it hangs there, check your network.
- Sliding-window on a big image prints "Processing N patches" and genuinely runs N patch inferences. On a 4K mosaic that's a lot of forward passes; if it feels slow, switch to scale mode or shrink the image first.
- CPU inference works but is painfully slow for a per-pixel model. Budget for it or skip it.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| device | COMBO | 2 options: cuda, cpu | |
| mode | COMBO | 2 options: scale, sliding_window | |
| threshold | FLOAT | 0.500–1 | — |
| patch_size | INT | 512128–1024 | Size of patches for sliding window mode |
| overlap | INT | 640–256 | Overlap between patches in sliding window mode |
| model_pathopt | STRING | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| probability_heatmap | IMAGE | — |
| binary_mask | IMAGE | — |
| mask | MASK | — |