Руководство по использованию Pipeline

Pipeline построен из этапов и передаёт один объект Page через все этапы:

detector -> layout -> recognizer -> corrector

По умолчанию Pipeline() создаёт:

  • детектор: YOLO(weights="yolo26x_obb_text_g1")

  • layout: SimpleSorting()

  • распознаватель: TRBA(weights="trba_lite_g2")

  • корректор: None

Контракты этапов

Детектор

Детектор должен реализовывать:

def predict(self, image) -> Page:
    ...

Распознаватель

Распознаватель должен реализовывать:

def predict(self, page: Page, image: Optional[np.ndarray] = None) -> Page:
    ...

Layout

Layout-модель должна реализовывать:

def predict(self, page: Page, image: Optional[np.ndarray] = None) -> Page:
    ...

Корректор

Корректор должен реализовывать:

def predict(self, page: Page, image: Optional[np.ndarray] = None) -> Page:
    ...

Базовое использование

from manuscript import Pipeline

pipeline = Pipeline()
result = pipeline.predict("document.jpg")
text = pipeline.get_text(result["page"])
print(text)

Отключение этапов

Необязательные этапы можно отключать через None:

from manuscript import Pipeline

# Detection + layout only
pipeline = Pipeline(recognizer=None, corrector=None)

# Detection + recognition only
pipeline = Pipeline(layout=None, corrector=None)

# Detection + layout + recognition (no correction)
pipeline = Pipeline(corrector=None)

Положение этапа layout

Используйте layout_after, чтобы выбрать, после какого этапа запускать layout:

  • "detector" (по умолчанию)

  • "recognizer"

  • "corrector"

from manuscript import Pipeline
from manuscript.layouts import SimpleSorting

pipeline = Pipeline(
    layout=SimpleSorting(),
    layout_after="recognizer",
)

Если опорный этап отключён, например recognizer=None при layout_after="recognizer", layout всё равно выполнится в этой позиции.

Встроенные компоненты

from manuscript.detectors import EAST
from manuscript.layouts import SimpleSorting
from manuscript.recognizers import TRBA
from manuscript.correctors import CharLM
from manuscript import Pipeline

detector = EAST(weights="east_50_g1", score_thresh=0.8, iou_threshold=0.2)
layout = SimpleSorting(max_splits=10, use_columns=True)
recognizer = TRBA(weights="trba_lite_g1", device="cuda", min_text_size=5)
corrector = CharLM()

pipeline = Pipeline(
    detector=detector,
    layout=layout,
    recognizer=recognizer,
    corrector=corrector,
    layout_after="detector",
)

Подготовка регионов в TRBA

TRBA поддерживает настраиваемую подготовку кропов перед распознаванием.

Настройки по умолчанию:

  • region_preparer="bbox" вырезает осеориентированные bounding box

  • rotate_threshold=1.5 автоматически поворачивает высокие кропы перед распознаванием

  • min_text_size=5 пропускает слишком маленькие детекции

Встроенные пресеты preparer:

  • "bbox": осеориентированный кроп

  • "polygon_mask": плотный кроп с маскированием пикселей вне полигона в белый цвет

  • "quad_warp": перспективное выравнивание для 4-точечных полигонов с переходом на bbox при необходимости

from manuscript.recognizers import TRBA

recognizer = TRBA(region_preparer="bbox")
recognizer = TRBA(region_preparer="polygon_mask")
recognizer = TRBA(region_preparer="quad_warp")
recognizer = TRBA(
    region_preparer="bbox",
    region_preparer_options={"pad": 2},
)

region_preparer_options зарезервирован для настройки встроенных пресетов:

  • "bbox" / "polygon_mask": pad

  • "polygon_mask": background

  • "quad_warp": output_size=(width, height), fallback_to_bbox

Для более сложных сценариев можно внедрить хуки в TRBA вместо того, чтобы писать полностью собственный распознаватель:

import numpy as np

def my_preparer(page, image, recognizer=None, options=None):
    regions = []
    for block in page.blocks:
        for line in block.lines:
            for text_span in line.text_spans:
                poly = np.asarray(text_span.polygon, dtype=np.float32)
                crop = image[10:40, 10:80]
                regions.append(
                    {"text_span": text_span, "image": crop, "polygon": poly}
                )
    return regions

recognizer = TRBA(region_preparer=my_preparer)

Если нужен полный контроль над логикой распознавания, самым простым вариантом по-прежнему остаётся собственный класс распознавателя с predict(page, image) -> Page.

Объединение TextSpan

Некоторые распознаватели работают с целыми строками или блоками, а не с кропами отдельных text span. Используйте collapse_page_text_spans, чтобы перед распознаванием преобразовать узкую структуру страницы в более широкую.

from manuscript.utils import collapse_page_text_spans

line_level_page = collapse_page_text_spans(
    page,
    level="line",
    method="bbox",
)

block_level_page = collapse_page_text_spans(
    page,
    level="block",
    method="convex_hull",
)

"line" сохраняет те же блоки и строки, но заменяет каждую строку одним объединённым TextSpan. "block" заменяет каждый блок одной строкой, содержащей один объединённый TextSpan.

Также доступны низкоуровневые вспомогательные функции:

  • merge_text_spans(text_spans, method="bbox")

  • collapse_line_text_spans(line, method="bbox")

  • collapse_block_text_spans(block, method="bbox")

Визуализация и профилирование

result, vis_img = pipeline.predict("document.jpg", vis=True)
vis_img.save("output_visualization.jpg")

result = pipeline.predict("document.jpg", profile=True)

Промежуточные результаты

После каждого запуска pipeline сохраняет снимки промежуточных результатов:

  • pipeline.last_detection_page

  • pipeline.last_layout_page

  • pipeline.last_recognition_page

  • pipeline.last_correction_page

Для пропущенных этапов соответствующее значение last_* остаётся None.