Document Page Detector

Модель находит страницы на длинном скриншоте документа и изображения внутри этих страниц.

Обучена для программы, которая режет длинные скриншоты на отдельные страницы: одна такая лента может содержать 8–20 страниц подряд.

Что делает

Модель возвращает рамки двух видов и различает их по уверенности:

Уверенность Что найдено
0.9 – 0.99 страница документа целиком
0.5 – 0.8 изображение внутри страницы
0.2 – 0.4 отдельный абзац, подпись, шум

Это важная особенность: разделять страницы и картинки по ширине рамки нельзя — у них почти одинаковая ширина. Разделяет именно уверенность.

Зачем нужна именно модель

Длинный скриншот — не сплошная лента: внутри страниц тоже есть крупные пустые промежутки между разделами (200–560 px), того же размера, что и разрывы между страницами.

Поэтому простой алгоритм «резать по пустым полосам» ошибается: на тестовом документе из 8 страниц он давал 13 кусков. Модель этот случай различает.

Архитектура

Faster R-CNN + ResNet-50-FPN (torchvision)
num_classes = 2   (фон + страница)
вход: до 1024 px по длинной стороне

Как использовать

import torch
from PIL import Image
from torchvision import transforms as T
from torchvision.models.detection import fasterrcnn_resnet50_fpn
from torchvision.models.detection.faster_rcnn import FastRCNNPredictor

model = fasterrcnn_resnet50_fpn(weights=None)
in_features = model.roi_heads.box_predictor.cls_score.in_features
model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes=2)

state = torch.load("trained_cutter_model.pth", map_location="cpu")
if isinstance(state, dict) and "model_state_dict" in state:
    state = state["model_state_dict"]
model.load_state_dict(state, strict=False)
model.eval()

image = Image.open("screenshot.png").convert("RGB")
width, height = image.size
scale = 1024 / max(width, height)
small = image.resize((int(width * scale), int(height * scale)), Image.BICUBIC)

with torch.no_grad():
    prediction = model([T.ToTensor()(small)])

boxes = prediction[0]["boxes"].numpy()
scores = prediction[0]["scores"].numpy()

# Страницы — только рамки с высокой уверенностью.
# 0.9 строго, 0.75 мягче: подбирается под формат съёмки.
scale_back = 1 / scale
pages = [
    tuple(int(c * scale_back) for c in box)
    for box, score in zip(boxes, scores)
    if score >= 0.75
]
print(f"найдено страниц: {len(pages)}")

Пороги уверенности

Задача Порог
Страницы 0.7 – 0.9
Изображения внутри страниц 0.4 – 0.5

Порог 0.5 для страниц не подходит: в результат попадут абзацы и подписи, и число «страниц» окажется завышенным.

Порог 0.9 строгий: если документ снят в другой ширине или с другой плотностью текста, часть страниц может не попасть в результат. На проверенном документе полный набор давал 0.7. Значение подбирается под конкретный формат съёмки.

Тестовый документ

В репозитории лежит test_document.png — лента 2476×12964 на 8 страниц. Содержимое синтетическое: текст про интернет-мемы о нейросетях, картинки нарисованы кодом. Ничего чужого, можно использовать для проверки.

Что должно получаться:

Порог Найдено страниц
0.9 6 — две последние теряются
0.8 6
0.7 8 — полный набор
0.5 8, но появляются лишние рамки на абзацах

Если результат при 0.7 отличается — модель стоит дообучить на своих документах.

Область применения

  • длинные скриншоты документов, снятые одним снимком;
  • страницы Google Docs, сохранённые одной лентой;
  • подготовка документа к постраничному распознаванию (OCR / vision-LLM).

Модель обучена на скриншотах узкого формата — длинная вертикальная лента шириной 1300–2500 px. На обычных горизонтальных фотографиях документов результат не гарантируется.

Ограничения

  • Документ должен быть снят одной лентой. Отдельные страницы A4 модель не ищет — для них нарезка не нужна.
  • При очень большой высоте (более ~15 000 px) уверенность падает: изображение сильно ужимается перед подачей в сеть.
  • Язык текста значения не имеет — модель работает с геометрией, а не с текстом.

Лицензия

MIT.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support