GROUT is a deep learning model for detecting and segmenting grout lines (mortar joints) in mosaic images. The model uses a U-Net architecture with an EfficientNet-B3 encoder, trained exclusively on procedurally generated synthetic data to achieve zero-shot transfer to real-world mosaics.
Author: Radoslav Lovecky, Arperon s.r.o., Institute of Advanced Technologies, Slovakia
Example: Input mosaic image β Detected grout lines (overlay) β Binary mask
Precise segmentation of tessellated surfaces is a challenge for cultural heritage documentation. GROUT overcomes the scarcity of annotated data by training on synthetic geometric priors. It generalizes to real-world Roman, Byzantine, and Modern mosaics without seeing a single real image during training.
- U-Net Architecture: EfficientNet-B3 encoder (~12M parameters).
- Zero-shot Transfer: Trained on 100% synthetic data, works instantly on real images.
- Multiple Geometry Support: Handles Opus Vermiculatum (flow lines), Opus Tessellatum (running bond), and irregular Voronoi.
- Sliding Window Inference: Processes gigapixel archival images at full resolution without downsampling artifacts.
- Robustness: Explicitly trained to ignore stone grain, dirt, and weathering artifacts.
Try GROUT online without installing anything: π Hugging Face Space
git clone [https://github.com/advancedtech-sk/GROUT.git](https://github.com/advancedtech-sk/GROUT.git)
cd GROUT
pip install -r requirements.txtDownload the model from Hugging Face:
# Using huggingface_hub
pip install huggingface_hub
python -c "from huggingface_hub import hf_hub_download; hf_hub_download('advancedtech-sk/GROUT', 'grout_b3_zeroshot_v1.pth', local_dir='checkpoints')"# Single image
python inference.py --image path/to/mosaic.jpg --model checkpoints/grout_b3_zeroshot_v1.pth
# Directory of images
python inference.py --input_dir path/to/images --model checkpoints/grout_b3_zeroshot_v1.pthpython generate_synthetic.pyThis generates 1,500 synthetic mosaic images with masks in data_local/:
- 40% Running Bond (brick pattern with parallel lines)
- 30% Opus Vermiculatum (concentric circles)
- 30% Voronoi (random tessellation)
Special modes:
- 15% Monochrome tiles (model must rely on grout lines only)
- 10% Zero grout (model must rely on color differences only)
python train.py --epochs 200 --batch_size 32 --encoder efficientnet-b3Prepare your data in data_finetune/images/ and data_finetune/masks/, then:
# Stage 1: Frozen encoder (safe adaptation)
python finetune.py --stage 1 --checkpoint checkpoints/grout_b3_zeroshot_v1.pth --data_dir data_finetune
# Stage 2: Unfrozen with low LR (gentle refinement)
python finetune.py --stage 2 --checkpoint checkpoints/finetune_stage1.pth --data_dir data_finetuneGROUT v1
βββ Encoder: EfficientNet-B3 (pretrained on ImageNet)
βββ Decoder: U-Net style with skip connections
βββ Input: 512x512 RGB images
βββ Output: Binary mask of grout lines
βββ Parameters: ~12M
GROUT/
βββ config.py # Configuration (hyperparameters, paths)
βββ dataset.py # Data loading and augmentation
βββ model.py # U-Net model definition
βββ losses.py # Dice, BCE, and combined losses
βββ utils.py # Metrics, visualization utilities
βββ train.py # Main training script
βββ inference.py # Inference and evaluation
βββ generate_synthetic.py # Synthetic data generator
βββ finetune.py # Fine-tuning script
βββ finetune_config.py # Fine-tuning configuration
βββ export_model.py # ONNX export
βββ requirements.txt # Dependencies
Key settings in config.py:
| Parameter | Default | Description |
|---|---|---|
IMG_SIZE |
512 | Input image size |
ENCODER |
efficientnet-b3 | Encoder backbone |
BATCH_SIZE |
32 | Training batch size |
LEARNING_RATE |
1e-4 | Initial learning rate |
DICE_WEIGHT |
0.5 | Weight for Dice loss |
BCE_WEIGHT |
0.3 | Weight for BCE loss |
The synthetic data generator creates realistic mosaic patterns:
- Running Bond: Parallel lines with offset vertical joints (brick pattern)
- Opus Vermiculatum: Concentric circles with random centers
- Voronoi: Random tessellation (400-1500 seeds)
- Random rotation and scaling
- Adaptive grout color (contrast against tiles)
- Realistic noise and blur
- Variable grout thickness (1-4px image, 2-3px mask)
# Evaluate on test set
python inference.py --evaluate --test_dir data_local --model checkpoints/best_model.pthMetrics:
- Dice Score: Overlap between prediction and ground truth
- IoU: Intersection over Union
- Precision/Recall: Detection accuracy
python export_model.py --checkpoint checkpoints/best_model.pth --output exports/grout.onnxIf you use GROUT in your research, please cite:
@software{grout2026,
author = {Lovecky, Radoslav},
title = {GROUT: Geometric Reasoning Over Unstructured Tessellations},
year = {2026},
publisher = {Zenodo},
doi = {10.5281/zenodo.18187264},
url = {https://doi.org/10.5281/zenodo.18187264}
}MIT License - see LICENSE file.