Spread Gutter Locator: where to cut a two-page spread
Finds the gutter (centre fold) line on a scan of a two-page spread, so the spread can be cut into left and right pages. Works on scans with extra background on one or both sides, when the gutter is not in the middle of the image.
Use it after Zhnivo/spread-classifier, which decides whether a scan is a spread at all.
Released by Zhnivo, a non-profit project preserving the archival heritage of Belarus.
Model
| Architecture | small convolutional network (about 90K parameters): 3ร3 convolutions pooled over height only, then a 1D head that scores every column |
| Input | grayscale scan resized to height 640; the central part of the width (30% to 70%) is resized to 256ร192 |
| Output | gutter position as a fraction of image width, a confidence score (0 to 1) and the source of the answer (network or fold_rule) |
| Fold check | by default the answer is checked against a classic fold rule (a column darker than its neighbours in all three thirds of the page, near the centre); if the rule finds a clear fold more than 5% of the width away, the rule wins. Turn it off with predict(..., use_rule=False) |
| Limitation by design | the gutter must lie within the central 40% of the image width |
| Hardware and speed | runs on an ordinary CPU, no GPU needed: about 6 spreads per second with the fold check and 12 without it, on a laptop CPU (AMD Ryzen 7, 6 threads), including reading the scans |
| Files | model.safetensors, config.json, inference.py |
Training data
Trained on spreads of printed and handwritten books, registers and archival files, mostly from the 19th and 20th centuries, with the gutter marked by hand. Validation spreads come from other books than the training spreads.
Usage
pip install torch safetensors pillow numpy scipy huggingface_hub
from huggingface_hub import snapshot_download
from PIL import Image
import sys
folder = snapshot_download("Zhnivo/spread-gutter-locator")
sys.path.insert(0, folder)
from inference import load_model, predict
model, cfg = load_model(folder)
(x, confidence, source), = predict(["spread.jpg"], model, cfg)
im = Image.open("spread.jpg")
cut = round(x * im.width)
im.crop((0, 0, cut, im.height)).save("left.jpg")
im.crop((cut, 0, im.width, im.height)).save("right.jpg")
Limitations
- Expects a two-page spread; on a single page it still returns a position.
- Tables whose wide gap between columns lies near the centre can mislead the model. Check results with low confidence.
License and attribution
MIT, free for any use. If you use the model, a link to the project zhnivo.com is appreciated.
- Downloads last month
- -
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐ Ask for provider support