2025, Oct 30 19:19

Пустая строка в Tesseract с chi_sim: причины и как исправить

Tesseract с chi_sim возвращает пустую строку? Причины и решения: качество изображения, контраст, выпрямление, порог. Пример вызова pytesseract и tessdata.

Когда Tesseract OCR возвращает пустую строку для китайского текста, хотя chi_sim установлен и виден инструментам, первая мысль — ошибка в настройке. На деле узким местом чаще оказывается само изображение. Шумная, низкоконтрастная фотография с перекосом и фактурным фоном легко опускается ниже порога, при котором Tesseract способен вообще выделить глифы.

Воспроизведение проблемы

Следующий фрагмент читает фото, преобразует его в изображение PIL и запускает pytesseract с chi_sim. Пакет языка на месте, но на выходе — пусто:

import cv2 as cv
from PIL import Image as PilImage
import pytesseract as ptes
from pyocr import tesseract as pyocr_tess
img_file = 'photo.jpeg'
cv_mat = cv.imread(img_file)
pil_frame = PilImage.fromarray(cv_mat)
result_text = ptes.image_to_string(pil_frame, lang='chi_sim')
print(result_text)

Проверка того, что язык обнаруживается, тоже проходит успешно:

import pytesseract as ptes
print(ptes.get_languages(config=''))  # ['chi_sim', 'eng', 'osd']

Что происходит на самом деле

Исходное изображение просто слишком плохое, чтобы Tesseract смог выделить и распознать символы. Перед распознаванием ему требуется несколько видов очистки: выпрямление для коррекции перспективы или поворота, повышение контраста, чтобы вытолкнуть передний план выше уровня шума, и цветовое пороговое разделение, чтобы убрать фактуру фона. Даже после обработки, если исходник низкого качества, результат может оставаться ниже приемлемого для обычного OCR.

Отсюда понятно, почему некоторые сервисы будто «магически» вытягивают чистый текст из таких снимков. Системы, агрегирующие множество похожих изображений, способны получить гораздо более чистое усреднение и прочитать то, что движок OCR в один проход не осилит. Для этого конкретного типа документа за счёт агрегации возможны, например, такие результаты:

中华人民共和国
居民身份证
签发机关
有效期限
2007.05.14-2027.05 14

Но даже хорошо очищенное одиночное изображение нередко уступает искусственно улучшенной интерпретации, полученной из нескольких экземпляров.

Что действительно помогает

Начинайте с картинки. Повышайте контраст, выпрямляйте область документа и применяйте цветовое пороговое разделение, чтобы подавить фон. Tesseract лучше всего работает с чёрным текстом на белом фоне и испытывает трудности, когда текст слишком мелкий или чрезмерно крупный; важна достаточная детализация, минимум 72 dpi. Если у вас единственная шумная фотография с фактурным фоном и низким контрастом, пустой или почти пустой результат закономерен.

Со стороны интеграции делайте ввод-вывод и окружение предсказуемыми. Загрузка напрямую в PIL избавляет от сюрпризов с цветовыми каналами: OpenCV читает в BGR, тогда как PIL ждёт RGB. Если читаете через OpenCV, убедитесь, что изображение не пустое, проверив его shape после imread: неверный путь может тихо вернуть непригодную матрицу. Полезно также запустить OCR из командной строки и сравнить поведение с вашим Python-стеком. При нетипичной вёрстке помогает настройка psm. А если каталог tessdata не лежит в стандартном пути поиска, может понадобиться явно передать его в config — даже если язык фигурирует в списке доступных пакетов.

Более надёжный вариант вызова в Python

Логика прежняя — загрузить изображение и вызвать image_to_string, — но эта версия устраняет неоднозначность BGR/RGB и показывает, как при необходимости передать путь к tessdata:

from PIL import Image as PilImage
import pytesseract as ptes
src_path = 'photo.jpeg'
lang_id = 'chi_sim'
# Если вашей системе нужен явный путь к tessdata, укажите его здесь; иначе оставьте пустую строку.
extra_cfg = '--tessdata-dir "/usr/share/tesseract-ocr/5/tessdata"'
img_obj = PilImage.open(src_path)
ocr_text = ptes.image_to_string(img_obj, lang=lang_id, config=extra_cfg)
print(ocr_text)

Это не создаст текст из принципиально нечитаемой фотографии, но снизит число ложных отрицаний, связанных с вводом-выводом или странностями конфигурации.

Почему это важно

Точность OCR определяется не только моделью и языковым пакетом. Она критически зависит от визуального качества входных данных и всей цепочки обработки. Понимание этих пределов помогает не гоняться за мнимыми багами в коде, когда узкое место — сами данные. Это также объясняет, почему некоторые сквозные системы превосходят одиночный вызов Tesseract на одном кадре: они шумоподавляют за счёт агрегации и применяют более жёсткий препроцессинг.

Практические выводы

Если Tesseract с chi_sim выдаёт пустую строку на шумном фото документа, займитесь изображением, а не только кодом. Выпрямите страницу, повысьте контраст и порогом подавьте фон, чтобы текст стал чёрным на белом. Убедитесь, что разрешение достаточно, и при нетипичной вёрстке подумайте о настройке psm. Загружайте изображения так, чтобы сохранить ожидаемые цветовые каналы, проверяйте, что вход действительно считался, и при необходимости явно передавайте каталог tessdata. Так вы отделите проблемы конфигурации от более частой реальности: картинка просто ниже порога качества для надёжного OCR.

Статья основана на вопросе на StackOverflow от пользователя showkey и ответе K J.