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) # оцінка виявлення, окрема від .confimport 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Кожен рядок називає зображення й перелічує його області:
{"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 і використовуйте
його шлях розгортання.