Предлагаемый вариант решения реализован под Windows-8, но с небольшими корректировками, думаю, вполне может быть использован для Linux и OS X.
С задачей преобразования изображения в текст справляются Abbyy FineReader, MS Word, MS OneNote.
Предлагаемое решение использует бесплатные утилиты. В приоритете также была работа в командной строке.
Преобразование всех страничек pdf в файлы изображений
Если бы страничек было 2-3, то можно было бы воспользоваться функцией PrintScreen. В Windows для этого есть отдельная кнопочка на клавиатуре. А в Mac OS X — хитрая комбинация клавиш: нужно нажать три клавиши Shift+Command+4, выбрать мышкой нужный участок экрана, и искать получившийся файл на рабочем столе. Но если страничек много, то нужно искать другой способ.
К счастью, есть программа StduViewer, которая позволяет это сделать. В меню Файл > Экспортировать > Как изображение. В появившемся окне выбираем тип PNG, разрешение 300 dpi, задаем путь, куда выложить получившиеся файлы изображений. В шаблоне имени сохраняемого файла стоит изменить %PN% на %0PN% для случая, если страничек больше 10.
kolgrim99 предложил для конвертации pdf-документа в jpg-файлы утилиту из пакета xpdf, которую можно использовать в командной строке. Вот его предложение:
<<Если стоит задача просто выпотрошить большой PDF файл со сканами (или любыми другими картинками), то можно использовать утилиту из набора xpdf, там куча всего, но для картинок нужна pdfimages.exe. Синтаксис примерно такой:
pdfimages.exe -j some_file.pdf C:\images\
причём в последнем аргументе в конце пути обязательно ставить '\', иначе не воспримет.>>
Преобразование файлов изображений страничек в текст
HP разработала, а Google открыла исходные коды библиотек tesseract, преобразовывающих изображения в текст (OCR). Устанавливаем программу tesseract-ocr.
Для распознавания русского языка при установке нужно в «Additional language data» взвести галочку для Russian.
В командной строке исполняем команды типа:
tesseract.exe image_01.png res_01.txt -l rus
Получаем текстовые файлы. Можно запустить команду для каждой странички вручную. Проще выполнить скрипт на python'е:
import os, sys
import io
sPathIn = "D:/Pictures/pict"
sPathOut = "D:/Pictures/txt"
sCmd = "\"C:/Program Files (x86)/Tesseract-OCR/tesseract.exe\" {} {} -l rus"
os.system("cd \"C:/Program Files (x86)/Tesseract-OCR\"")
dirs = os.listdir( sPathIn )
for file in dirs:
filename, file_ext = os.path.splitext(file)
sCmdRes = sCmd.format(sPathIn + '/' + file, sPathOut + '/' + filename + ".txt")
print ("run> " + sCmdRes)
os.system(sCmdRes)
Получилась кучка текстовых файлов, которые осталось объединить в один. Это можно сделать ручками. Но проще было написать скриптик на python'е:
import os, sys
import io
sPathIn = "D:/Pictures/txt"
sFileOut = "D:/Pictures/res.txt"
dirs = os.listdir( sPathIn )
for file in dirs:
filename, file_ext = os.path.splitext(file)
if (file_ext == ".txt"):
fOut = open(sFileOut, "ab")
f = open(sPathIn + "/" + file, "rb")
data = f.read()
fOut.write(data)
f.close()
fOut.close()
На этом можно было бы закончить, т.к. в основном текст получился вполне читабельным, но местами в тексте образовалась масса оЧЕпЯток.
Например, картинка с текстом
преобразовалась в нечто такое:
управление процессом моделирования, в том числе посредствомвременного прерывания, промежуточного сохранения и повторного запускапроцесса моделирования из приостановленного состояния, задания различныхначальных условий, введа отказов бортовых систем, метеоусловий, временисуток, различных возмущающих факторов (ветер, турбулентность и др.);
Поэтому появился следующий этап.
Исправление ошибок в тексте
Воспользуемся программой LanguageTool. Нас интересует работа в командной строке, поэтому скачиваем «независимую версию». Для работы с LanguageTool требуется Java.
Запускал из родного каталога (на Windows-8.1 оно почему-то не захотело работать, если текущий каталог — чужой) и указывал полные имена файлов (с каталогом). Если в командной строке выполнить команду, например, такую:
java -Dfile.encoding=UTF-8 -jar languagetool-commandline.jar --help
… то запустится дополнительная консолька, где честно напишет help и благополучно закроется в течение секунды. Чтобы видеть, чего же оно пишет в консоль, нужно запускать командный bat-файла с этой строкой внутри. Возможно, у java есть ещё какой-нить параметр командной строки, чтобы не запускалась доп. консоль, но мне сие неведомо.
Команда исправления ошибок в текстовом файле получилась такая:
java -Dfile.encoding=UTF-8 -jar languagetool-commandline.jar -a -l ru original.txt > corrected.txt
Чтобы отключить исправление маленьких букв на большие в начале строк появились дополнительные параметры --disablecategories CASING, а вместо имени файла — %1, чтобы имя передавать внутрь bat-файла в качестве аргумента. Итого, строка в bat-файле получилась такая:
java -Dfile.encoding=UTF-8 -jar languagetool-commandline.jar -a -u --disablecategories CASING -l ru %1 > %1-res.txt
По аргументу -u в конец исправленного текстового файла добавляется строка «Unknown words:» с перечислением через запятую всех слов, которые LanguageTool не знает. Таким образом, можно улучшить текст, исправив неправильные слова из этого списка.
Был использован Python 3.5 и PyCharm.
Спасибо за внимание!
Комментарии (60)
Taciturn
02.11.2016 16:26+1Берём FineReader и всё, пусть местами и кривовато, работает.
geher
02.11.2016 16:37+3И получим наиболее качественный вариант.
Одна только проблемка. Оно денег хочет (страничек у нас по условию задачи много).
Есть бесплатный вариант. Cuneiform. Качество будет средней паршивости.
LoadRunner
02.11.2016 17:01+3БерёмПокупаем FineReader, Вы хотели написать?third112
02.11.2016 19:37И я, читая, вспомнил про FineReader. Доволен его работой. (Правда, распознавать приходится не часто).
kolgrim99
02.11.2016 22:16Владельцам МФУ на заметку. Раньше тоже «брал» FineReader, но как-то от нечего делать шарился по дампам CD дисков с драйверами и в одном из дисков от МФУ обнаружил инсталлятор очень приличной платной распознавалки, называлась Read Iris (согласно лицензионному соглашению её можно было использовать вместе с МФУ, была фулл версия, русский + английский, с логотипом HP в инсталляторе и без всяких серийников), а на другом диске от второго МФУ обнаружилась какая-то версия FineReader. С тех пор проблема с лицензией для меня отпала.
tarpedo
02.11.2016 16:44+2Отличная статья. Только сегодня ночью прикручивал tesseract к telegram, skype и whatsapp ботам. Спасибо за идею с исправлением ошибок. Клиенты нашей CRM сильно обрадуются этой функции, другим разработчикам советую взять на заметку.
Один из примеров использования, фотография документа в чат к боту и в ответ приходит распознанный текст который можно использовать при помощи копипаста. Значительно упрощает использование мобильных устройств для автоматизации бизнес процессов.
Также она умеет распознавать штрихкоды, фотографии ценников в магазинах от мерчика сразу с геометкой уходят в базу клиента в структурированном виде. Только один раз немного нужно подрихтовать распознавание под каждую сеть магазинов.
baldr
02.11.2016 16:48+5Честно говоря, по своему опыту, если вижу на горизонте задачу «сделать экспорт отчетов в PDF» или, упаси Нортон, «перевести документы с таблицей из PDF во что-то другое» — предпочитаю сразу избавиться от этой задачи…
Если с экспортом еще можно что-то придумать через различные html2pdf-утилиты разной степени ущербности, то парсинг PDF — это тот еще адок… Внутренняя структура представляет из себя набор блоков контента с координатами. Причем в блоке могут быть как отдельные буквы, так и столбцы (!) букв. Преобразовать это все во что-то машиночитаемое, поверьте мне, не так легко.
Блоки могут перекрываться, но на экране этого не видно, однако при парсинге вы наверняка выучите размеры ширины и высоты всех символов используемых шрифтов.
Интересная идея перевести PDF в картинку и распознать. Однако, любое распознавание — это, как и замечено в статье, — с определенной вероятностью путь к опечаткам. Если процесс надо автоматизировать, а в файлах содержатся цены или точные данные — то любые опечатки могут быть довольно болезненны. Тем более что в PDF, вроде бы, есть эти данные и использовать их — вроде бы логичнее.
Что касается html2pdf — на первый взгляд все выглядит довольно удобно. Утилит и библиотек достаточно много разных. Вроде бы и html в виде странички с отчетом у вас уже есть, но не все так просто…
Внезапно оказывается, что стили этот конвертор понимает по-своему, некоторые css-фичи не поддерживаются совсем, выкидывая в процессе критическую ошибку на "@" символы. Да и результат почему-то оказывается совсем не таким как на экране — все плывет и не умещается на экран… Стили из bootstrap совершенно не работают…
Ах да, у нас на страничке были графики из chart.js? Клиенту они очень нравятся и он хочет их тоже видеть в отчете? Okay…
Для конечного пользователя PDF выглядит очень удобным, переносимым, удобным при печати, поэтому его и просят везде. Но работать с ним изнутри… Ну нафиг…
Как это было у меняУ меня был следующий опыт — изначально задача ставилась как «отобразить отчеты с фильтрами на страничке из базы». Довольно просто, ок.
После этого клиент просит добавить графики. Ок, chart.js выглядит красиво — делаем. Рисуем на фронтенде, данные приходят через API.
Внезапно следующая просьба — сделать экспорт один-в-один в csv/xls/pdf. Чувствую, что это не так уже просто. CSV — это текст, не проблема… XLS умеет графики сам рисовать довольно просто, тоже решается.
А вот с PDF начинается цирк. Допустим, таблицы с грехом пополам я там нарисовал, а вот для графиков придумал «грязный хак» — при клике юзером кнопки «PDF» все графики на страничке жабаскриптом переводятся в картинки и отправляются на бэкенд, где просто вставляются в PDF. Выглядят так же и чертить оси-масштабы-легенды не надо.
Я понял что идея была плохой, когда клиент в следующий раз попросил сделать 'njn экспорт по расписанию автоматически, отправляя отчет по почте с PDF-вложением… Эту задачу решал уже не я, а другой разработчик, который это сделал через matplotlib.Yanovets
02.11.2016 17:15Речь в статье о pdf, который содержит не текст, а картинки, т.е. отсканированный документ.
sasha1024
02.11.2016 19:36+2Та ладно… Из HTML в PDF достаточно простая задача. Только не надо съезжать в «быстрые» решения вроде html2pdf.
PDFCreator же как-то в PDF печатает. Браузеры могут, LibreOffice может. Просто задействовать API существующих программ.
Как лобовой вариант (возможно, сейчас не самый эффективный): сохранить html с картинками на диск, открыть с помощью LibreOffice API, сохранить с помощью LibreOffice API в PDF. Точнее, даже сохранять на диск не обязательно, можно прямо с http открыть. Возможно, сейчас эффективнее будет задействовать API браузеров (не знаю, не пробовал).
Я в своё время прошёл следующую эволюцию:
1. Html2pdf (говно).
2. Apache FOP. Может преобразовывать XSL-FO в PDF. XSL-FO — это специальный язык разметки (аналогичный HTML, только для разбиваемых на страницы документов, а не бесконечно вертикально протяженных; т.е. те нюансы форматирования, которые html2pdf пытается решить введением дополнительных keyword'ов в HTML и соответственно отходом от полноценной поддержки нормального HTML, при использовании FOP решены системно использованием стандартизованного и продуманного языка). Навострившись в XSL-FO, можно генерить документы прямо в нём.
3. OpenOffice.org (тогда ещё не было LibreOffice) API.
При этом можно автоматически преобразовывать ODF-документы в XSL-FO, установив в OpenOffice некоторые расширения (по сути, XLST-фильтры, добавляющие поддержку дополнительных форматов). Это если захотите комбо 3+2. А ещё ODF-документы можно генерить напрямую.
P. S.: А обратно да, обратно конечно нафиг, не стоит
ninedraft
04.11.2016 22:08+1Я недавно открыл для себя athenapdf
Честно говоря, решение довольно громоздкое, но результат рвёт html2pdf как тузик грелку, да и в использовании гораздо проще
zvyagaaa
02.11.2016 17:06+5Самый простой и качественный для меня вариант был открыть файл PDF Word'ом. Который 365. Он при открытии PDF файла его распознает. И почему-то распознает у меня лучше, чем FineReader. А так как Word входит в комплект офиса, который у меня и так стоит, то файнридером я больше не пользуюсь.
Yanovets
02.11.2016 17:18-2Речь в статье о pdf, который содержит не текст, а картинки, т.е. отсканированный документ. Word не умеет из картинок делать текст. FineReader умеет.
zvyagaaa
02.11.2016 17:23+2вообще-то именно картинки и распознавались, сами попробуйте.
zvyagaaa
02.11.2016 17:30+2http://rgho.st/8zPF4Rfw6 исходный PDF
http://rgho.st/7pzTWYvbf файл, который создал сам Word 365 (он же 2016)Yanovets
02.11.2016 18:18+1Да, действительно. Не знал, что они 365-й Word обучили преобразовывать в текст. Спасибо за информацию.
А ошибки там, кстати, такие же, как и в случае с tesseract'ом. Например, слово «также» превратилось в некое «таюке» :). Так что исправление опечаток все ещё актуально.darkdaskin
03.11.2016 19:37+1Офис довольно давно умеет распознавать текст. Используя бесплатную OneNote, получить текст из PDF можно в 2 клика:
- Вставка -> Распечатка.
- ПКМ по любой странице -> Копировать текст со всех страниц.
Аналогично можно распознавать и другие форматы, например DJVU, открыв документ в соответствующем приложении и отправив на печать на виртуальный принтер OneNote.
Yanovets
04.11.2016 22:21Да, хорошее, простое решение — ставлю «лайк». Но если бы я выбрал такое простое решение, то на python'е не удалось бы попрограммить :). И ещё плюс моего решения — практически все вопросы решаются из командной строки (т.е. можно автоматизировать процесс при желании), с небольшими допилами можно использовать на других операционных системах. И кроме того, от последнего этапа — исправление ошибок — OneNote, скорее всего, не избавляет. Или по опыту текст совсем чистенький получается?
luciana
02.11.2016 18:03+6Здравствуйте! Я из ABBYY. Наши разработчики прочитали ваш комментарий и просили передать, что завели рекламацию и будут исправлять этот момент в файнридере.
third112
02.11.2016 19:57+1Здравствуйте!
Пользуясь случаем, во-первых хочу поблагодарить за удобную программу (FineReader), а во-вторых подкинуть идею вашим разработчикам. Для математических текстов (в том числе и текстов по CS, нпр., с описанием алгоритмов) очень часто используют TeX/LaTeX. Но иногда текст доступен только в pdf. Вот бы сделали возможность распознавать с мат. формулами в TeX/LaTeX, а то, нпр., часто бывает необходимость цитировать мат.тексты.57DeD
03.11.2016 19:17Всё никак не соберёмся делать распознавание математических формул — никто не верит, что дело окупится.
Косвенное свидетельство тому — пока нет хорошо работающего изделия изговна и палокперебора гипотез отношений и Tesseract'а.
kelegorm
02.11.2016 18:02Кстати, а что если так: берем пдф, который текстом, блоками, фигачим его в картинки, сохраняем разметку где картинке какой блок соответсвует и полу-распознаем текст. То есть по сути, мы просто через преобразование в картинку и распознавание картинки визуально переделываем блоки пдф. В итогде можно получить почти безошибочный документ. Ошибок распознавания символов не будет, будет беда только с ошибками распознавания таблич, содержаний и наверное структуры заголовков, пометок страниц — номера, имя главы.
Я очень давно хочу получить тулз для переваода пдф в нормальные электронные документы. Если речь идет об электронных книгах, то в основном предлагают вариант, где каждая строка пдф — это отдельный абзац. И текст получается фиксированной ширины.handicraftsman
02.11.2016 20:01-21. Берём PDF. Желательно крупный. Желательно на нескольких языках.
2. Конвертируем его в pdf-картинки (сохраняя оригинал).
3. Обучаем исходниками и результатом нейросеть
4.…
5. Profit!
venompro
02.11.2016 21:48Сергей, а как связаться с Вами можно?
Хочу посоветоваться, есть похожая задача на распознавания товаров и цен к ним из PDF.
kolgrim99
02.11.2016 23:11+2Если стоит задача просто выпотрошить большой PDF файл со сканами (или любыми другими картинками), то можно использовать утилиту из набора xpdf, там куча всего, но для картинок нужна pdfimages.exe. Синтаксис примерно такой:
pdfimages.exe -j some_file.pdf C:\images\
причём в последнем аргументе в конце пути обязательно ставить '\', иначе не воспримет.
praeivis
03.11.2016 08:53+3Получилась кучка текстовых файлов, которые осталось объединить в один. Это можно сделать ручками. Но проще было написать скриптик на python'е
А можно просто одной командой: copy *.txt vestext.txtYanovets
03.11.2016 09:08-2Ага. Полностью согласен. Предложенная Вами команда гораздо короче, поэтому быстрее. Мне просто было интереснее сделать это на python'е :). И есть ещё один хороший плюс у python'овского кода — кроссплатформенность. Т.е. его можно выполнить на Windows, OS X, Linux, и т.д.
erdbeeranke
05.11.2016 23:22ваш код на питоне просто ужасен:
- он не кроссплатформенный, чего только стоит разделитель путей '/'
- в строках запутывающие экранирования, когда можно просто использовать одиночные кавычки
- открытие файла без with или try
- ой, всё
Yanovets
05.11.2016 23:51Так не было намерений написать красивый, в рюшечках код. И, возможно, у нас с Вами разные представления о том, что такое ужасно, а что такое прекрасно :). Это ж дело вкуса. Возможно, если Вы выложите здесь пример Вашего совершенного кода, он может показаться кому-то ужасным. То, что я написал — это одноразовый код — написал, получил результат и забыл. Если у Вас есть желание его повторно использовать, и сделать кроссплатформенным с обработкой исключений — пожалуйста. Только это потребует дополнительных строчек кода, а значит — времени. Может, это не очень красивый код, зато это код проверенный и работающий. Вы можете его использовать прям сходу для решения целевой задачи. Ну, и что там говорить — в python'e это мои первые шаги, поэтому где-то могу писать не оптимально.
Yanovets
06.11.2016 16:141) А чем плох разделитель путей '/'? Этот-то как раз более кроссплатформенный, чем такой — '\\'. И ещё вот такой '/' лучше, потому что не требует «запутывающего экранирования». Так что отметаю полностью это Ваше замечание. Пока не представите более убедительные доказательства ужасности прямого слэша.
2) Насчёт одинарных кавычек — согласен. Можно было. Мне просто привычнее двойные.
Имеется ввиду, как я понимаю, такое использование кавычек:
3) И насчёт with — в принципе согласен. С файлами лучше использовать его. Даже в коде на скорую руку. По крайней мере потому, что вызов close тогда не нужен. Имеется ввиду такой код:sCmd = '"C:/Program Files (x86)/Tesseract-OCR/tesseract.exe" {} {} -l rus'
with open(sFileOut, "ab") as fOut:
erdbeeranke
10.11.2016 16:02+11) разделитель путей "/" плох тем, что это магическая переменная. возможно в виндовсе она будет работать. но лучше использовать os.sep, который точно будет работать в той системе, в которой выполняется код. ещё лучше использовать os.path.join() для того, чтобы составлять путь.
2) да.
3) да.
код должен быть красивым и понятным, если его показывать людям.
если код красивый и понятный, его можно понять и через год.Yanovets
11.11.2016 12:38Разделитель "/" будет работать в Windows, Linux, OS-X. Согласен, что в идеальном коде нужно использовать os.sep. Но в неидеальном одноразовом коде, когда закопипастить путь (как я и сделал в приведенном коде) проще, чем составлять путь из кусочков. Наглядность, кстати, тоже пострадала бы, если бы я использовал не слэши (на мой взгляд). Хотя, конечно, пути лучше в коде не хранить, держать их где-нить в конфигах. Тогда отпадет необходимость в использовании слэшей в коде. Так что принципиально с замечанием согласен.
<<код должен быть красивым и понятным, если его показывать людям.
если код красивый и понятный, его можно понять и через год.>> — золотые слова!!! подписываюсь под каждой буквой!
senka1978
04.11.2016 16:49А русский язык к tesseract как подключили?
У меня ругается
Failed loading language 'rus'
Tesseract could't load any languageYanovets
04.11.2016 16:50Для распознавания русского языка при установке tesseract'а нужно в «Additional language data» взвести галочку для Russian. Если не поможет, т.е. русский уже установлен, то попробуйте сделать текущим каталогом tesseract.
pantlmn
04.11.2016 22:54У меня нормально tesseract распознал приведенную картинку (OS X 10.8).
временного прерывания, промежуточного сохранения и повторного запуска
процесса моделирования из приостановленного состояния, задания различных
начальных условий, ввода отказов бортовых систем, метеоусловий, времени
суток, различных возмущающих факторов (ветер, турбулентность и др.);
У Вас как-то неправильно обрабатываются концы строк.Yanovets
06.11.2016 16:27Приведённый текст — это часть странички, которую tesseract должен был преобразовать. Может, tesseract лучше отрабатывает, если ему скармливать меньше текста? Загадка.
pantlmn
07.11.2016 02:18Нет, тут вопрос не в кусочке страницы, а в обработке концов строк. Все приведенные в примере ошибки связаны лишь с тем, что пропали концы строк. Скорее всего, это связано с тем, tesseract выдает в unix-формате только с LF, а windows хочет видеть CR+LF. Посмотрите в википедии, там есть и подсказки, как это поправить.
Yanovets
07.11.2016 22:40Да, это Вы хорошо подметили — насчёт концов строк. Посмотрел. Tesseract выдает текст в кодировке utf-8. Перевод строк — два символа \x0A+\x0A. Там, где в результате работы tesseract слова без пробела — один символ \x0A. Ну, с этой проблемой легко справился LanguageTool. Спасибо за замечание!
Slipeer
Есть пример входного и выходного файла для которого это работает?
А то я по-быстрому заскринил статью из opennet — прогнал скрин через tesseract 3.03 — получилась редкостная чушь.
А ещё, подозреваю, что таблицы оно не понимает… никак…
Yanovets
Пример картинки и результат полученного текста привел в статье.
Насчёт таблиц — не знаю, не пробовал.
Yanovets
А ещё совсем плохой текст получался, когда я скормил tesseract'у картинку с разрешением < 300 dpi.
argz
Со скриншотами вечная проблема. Количество пикселей на букву очень мало, если сравнивать с фотографией или сканом страницы.