OCR

OCR знаходить текст на зображенні та читає його. LibreYOLO надає це як задачу ocr, що повертає один чотириточковий полігон і одну транскрипцію для кожної текстової області в порядку читання.

Визначення

Задача ocr виконує дві дії за один виклик: знаходить кожну текстову область на зображенні й транскрибує її. Області повертаються як чотириточкові полігони, а не вирівняні за осями рамки, оскільки текст на сценах часто повернутий, і впорядковуються для читання згори вниз, потім зліва направо.

Передбачення заповнює result.ocr, корисне навантаження OCRRegions. .data, це масив float (N, 4, 2) полігонів у пікселях вихідного зображення з порядком верхня ліва, верхня права, нижня права, нижня ліва; .texts, список із N транскрипцій; .conf, оцінка розпізнавання для кожної області, а .det_conf, оцінка виявлення; .xyxy дає вирівняну за осями оболонку кожного полігона. Оскільки чотирикутники є справжніми полігонами, вони не заповнюють result.boxes. Зріз OCRRegions переносить транскрипції та обидва масиви оцінок разом із геометрією.

Моделі

Задачу ocr обслуговують два сімейства.

PP-OCRv5, це спеціалізований конвеєр: детектор із диференційованою бінаризацією знаходить чотирикутники тексту, а розпізнавач SVTR/CTC читає їх; обидва етапи входять до одного файла .pt разом із набором символів розпізнавання. Він постачається у двох рівнях, легшому для CPU й серверному для вищої точності, а один словник охоплює спрощену та традиційну китайську, англійську, японську й піньїнь.

SenseNova-Vision виконує OCR, генеруючи слова як розмічений текст із тієї самої контрольної точки 7B, що обслуговує шість інших задач, завантаженої через LibreVLM("sensenova-vision", task="ocr"). Їй потрібна додаткова залежність sensenova, а ваги обмежено некомерційним використанням; ліцензію наведено на її сторінці.

Передбачення

Під час першого використання ваги завантажуються з Hugging Face і кешуються локально.

Читання тексту на зображенні
from libreyolo import LibreYOLO, SAMPLE_IMAGE # Рівень t є легшим із двох і створений для CPU. SAMPLE_IMAGE# дає змогу запустити приклад; укажіть власне зображення з текстом.model = LibreYOLO("LibrePPOCRt-ocr.pt")result = model(SAMPLE_IMAGE) regions = result.ocrprint(len(regions), "regions")for text, score in zip(regions.texts, regions.conf):    print(repr(text), float(score))
Читання чотирикутників
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibrePPOCRt-ocr.pt")result = model(SAMPLE_IMAGE) regions = result.ocrprint(regions.data.shape)   # полігони (N, 4, 2), ЛВ ПВ ПН ЛНprint(regions.xyxy)         # вирівняні за осями оболонки цих полігонівprint(regions.det_conf)     # оцінка виявлення, окрема від .conf
Фільтрування за впевненістю розпізнавання
import numpy as npfrom libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibrePPOCRt-ocr.pt")result = model(SAMPLE_IMAGE) # Індексуйте позиціями, а не логічною маскою: зріз переносить# транскрипції й обидва масиви оцінок разом із геометрією.regions = result.ocr.numpy()keep = regions[np.flatnonzero(regions.conf >= 0.9)]print(keep.texts)

PP-OCRv5 виконує виявлення з фіксованим обмеженням довгої сторони, а потім розпізнає обрізані області пакетами; rec_batch керує кількістю фрагментів за один прямий прохід розпізнавача. Джерела з кількома зображеннями обробляються послідовно, оскільки двоетапний конвеєр не створює спільні пакети між зображеннями. Джерела, потокову обробку й роботу з результатами описано в розділі передбачення.

Формат датасету

Мітки OCR зберігаються в одному файлі JSONL на поділ, по одному об'єкту JSON на зображення, поруч із самими зображеннями.

my-ocr-dataset/
  images/
    val/receipt.jpg
  labels/
    val.jsonl

Кожен рядок називає зображення й перелічує його області:

json
{"image": "receipt.jpg", "regions": [{"polygon": [[10, 12], [118, 14], [117, 40], [9, 38]], "text": "TOTAL 12.50"}]}

polygon, це чотирикутник в абсолютних піксельних координатах у порядку верхня ліва, верхня права, нижня права, нижня ліва. Область із текстом, який неможливо прочитати, позначається "text": "###" за угодою ICDAR don't-care: вона не враховується в оцінюванні розпізнавання, а передбачення, що її перекриває, ігнорується замість підрахунку як хибно позитивного.

Достатньо передати кореневий каталог як data=. Альтернативою є YAML датасету з path, необов'язковими назвами каталогів images і labels, а також nc: 1 і names: {0: text} як заповнювачами схеми, оскільки модель OCR повертає Results.ocr, а не виявлення. Повний контракт описано у форматах датасетів.

Навчання

Жодне сімейство OCR не має реалізації навчання: train() спричиняє NotImplementedError для обох, а підтримка OCR охоплює лише передбачення та валідацію. На сторінці PP-OCRv5 вказано код навчання upstream за Apache-2.0 і скрипт перетворення для повернення донавченої контрольної точки до LibreYOLO.

Валідація

val() оцінює весь конвеєр, виявлення й розпізнавання разом, зіставляючи передбачені полігони з еталонними взаємно однозначно за IoU понад 0.5.

Валідація й читання ключів метрик
from libreyolo import LibreYOLO model = LibreYOLO("LibrePPOCRt-ocr.pt")metrics = model.val(data="my-ocr-dataset") print(metrics["metrics/det_precision"], metrics["metrics/det_recall"])print(metrics["metrics/det_hmean"])print(metrics["metrics/e2e_f1"])       # fitnessprint(metrics["metrics/rec_1-NED"])

metrics/det_precision, metrics/det_recall і metrics/det_hmean оцінюють лише локалізацію: для збігу потрібне лише перекриття полігонів незалежно від транскрипції. metrics/e2e_precision, metrics/e2e_recall і metrics/e2e_f1 додають читання: для збігу потрібні те саме перекриття полігонів і точний збіг транскрипції після нормалізації NFKC та вилучення пробілів, із урахуванням регістру. metrics/e2e_f1 також є fitness, тобто значенням для вибору найкращої контрольної точки.

metrics/rec_1-NED окремо оцінює розпізнавач за парами, уже зіставленими детектором: одиниця мінус нормалізована відстань редагування, тому транскрипція з помилкою в одному символі отримує значення біля 1 там, де наскрізна F1 дає 0.

Експорт

Для цієї задачі немає доступного формату експорту. PP-OCRv5 складається з двох мереж, що працюють разом, а не одного графа для трасування, і export() спричиняє помилку для кожного формату в обох сімействах. Для розгортання поза LibreYOLO виконайте донавчання в upstream і використовуйте його шлях розгортання.

Перевірено з LibreYOLO v1.5.0.