Pull to refresh

Создаём приложение на С++ с использованием Tesseract-ocr, MinGW и напильника

Reading time6 min
Views30K
Так случилось, что понадобилось нам внедрить в своё приложение возможность распознавания текста, поэтому начались поиски подходящей библиотеки. В конечном счёте остановились на двух опенсорсных проектах CuneiForm Linux и Tesseract-ocr. Внимательное изучение проекта CuneiForm показало, что это просто порт продукта компании Cognitive Technologies, исходники которого они открыли в 2008 году и благополучно забили получив свою порцию внимания (во всяком случае такое сложилось впечатление). По сути весь проект состоял в портировании, а о новых фичах даже речи не шло. Всё это, вкупе с печальной новостью на страничке проекта, заставило нас отказаться от CuneiForm в пользу Tesseract, который в данный момент принадлежит Google, что даёт некоторую уверенность в будущем проекта. Под катом опыт сборки Tesseract-ocr под Windows с использованием MinGW и последующего создания простейшего приложения на С++.

Подготовка


Я постараюсь описать всё что нужно сделать, чтобы собрать tesseract с минимальной головной болью, при этом постараюсь не углубляться в банальности.

Установка и настройка MinGW

Скачиваем и устанавливаем последний доступный инсталлятор с официального сайта проекта, не забываем выставить галочки для C++ Compiler и MSYS Basic System. После этого заходим в MinGW Shell и устанавливаем дополнительные пакеты, которые понадобятся нам позже, следующей командой:
mingw-get install mingw32-automake mingw32-autoconf mingw32-autotools mingw32-libz
Сразу заметим, что в /mingv примонтирован каталог, в который установлен MinGW, это нам также пригодится при сборке библиотек.

Устанавливаем библиотеку Leptonica

Tesseract-ocr использует для работы с изображениями библиотеку Leptonica, я опишу как собрать и установить её из исходных кодов, которые можно взять с официального сайта, но перед этим нам нужно установить библиотеки libJpeg, libPng и libTiff, которые в свою очередь использует Leptonica (сделаем это также сборкой из исходных кодов).

Сборка libJpeg

Скачиваем архив с исходными кодами с официального сайта и распаковываем в отдельный каталог (для простоты будем считать, что это D:\lib\jpeg). Возвращаемся в MinGW Shell и лёгким движением руки собираем и устанавливаем библиотеку в каталоги, в которых gcc ищет по умолчанию. Флаги переопределяем чтобы отключить вывод отладочных символов.
cd /D/lib/jpeg
./configure CFLAGS='-O2' CXXFLAGS='-O2' --prefix=/mingw
make
make install


Сборка libPng

Также скачиваем архив с исходными кодами со странички проекта и распаковываем в каталог D:\lib\png (Вы, естественно, можете выбрать другой). Возвращаемся в MinGW Shell и повторяем то же самое, что и для libJpeg.

Сборка libTiff

Архив с исходными кодами берём с рекомендуемого ftp и распаковываем в D:\lib\tiff. И собираем аналогично предыдущим двум.

Сборка Leptonica

Архив с исходными кодами у нас уже есть, осталось его распаковать в D:\lib\leptonica. А дальше впору вспомнить про напильник, сборка с поддержкой Zlib не удастся из-за небольшого бага, который впрочем легко исправить самостоятельно. Для этого открываем файл src/pngio.c, расположенный в каталоге, куда мы распаковали исходники Leptonica. Там необходимо найти строку #include «png.h» и вставить после неё директивы, чтобы получилось примерно вот так:
#include "png.h"

#ifdef HAVE_LIBZ
#include "zlib.h"
#endif

/* ----------------Set defaults for read/write options ----------------- */

После этого собираем Leptonica так же как и предыдущие библиотеки.

Сборка и установка Tesseract-ocr


Теперь у нас есть все необходимые зависимости. Скачивать исходники на этот раз будем из транка svn разработчиков:
svn checkout ht tp://tesseract-ocr.googlecode.com/svn/trunk/ tesseract-ocr-read-only
*пробел между t преднащначен исключительно для хабрапарсера, уберите его.

После чего опять берёмся за напильник, я же предварительно сэкспортировал исходники в D:\lib\tesseract.
Пути к файлам я буду писать относительно каталога, в котором находятся исходники tesseract (напомню, что в моём случае это D:\lib\tesseract).
  • Редактируем файл ccutil/platform.h. Нам нужно закомментировать повторное объявление типа BLOB, которое уже есть в winsock2.h. Должно получиться, что-то вроде:
    /*typedef struct _BLOB {
    unsigned int cbSize;
    char *pBlobData;
    } BLOB, *LPBLOB;*/
  • Из vs2008/port копируем файлы strtok_r.h и strtok_r.cpp в каталог ccutil и добавляем strtok_r.cpp в переменную libtesseract_ccutil_la_SOURCES в файле ccutil/Makefile.am.
  • Комментируем объявление класса PBLOB в api/baseapi.h.
  • В файле api/Makefile.am дополняем переменную AM_CPPFLAGS значением -I$(top_srcdir)/vs2008/port
    или просто копируем файл vs2008/port/version.h в каталог api
  • Дополняем переменную AM_CPPFLAGS в файле viewer/Makefile.am значением -I$(top_srcdir)/ccutil

После этих манипуляций можно перейти в MinGW Shell и приступить к непосредственной сборке библиотеки:
cd /D/lib/tesseract
./runautoconf
./configure CFLAGS='-D__MSW32__ -O2' CXXFLAGS='-D__MSW32__-O2' LIBS='-lws2_32' LIBLEPT_HEADERSDIR='/mingw/include' --prefix=/mingw
make
make install

Пока он собирался я успел попить чаю, а после обнаружил пачку заголовочных файлов в /mingw/include/tesseract, заголовочные файлы Leptonica расположились в /mingw/include/leptonica, все библиотеки закономерно оказались в /mingw/lib.

Простое приложение


Я приведу код целиком, так как он весьма мал:
#include <stdio.h>
#include <string.h>
#include <tesseract/baseapi.h>
#include <leptonica/allheaders.h>

int main(int argc, char* argv[]) {
    tesseract::TessBaseAPI tessApi;
    tessApi.Init("data", "rus");// тут data каталог в котором лежат файлы *.traineddata,
    // а rus указывает какой именно из них использовать
    if(argc > 1) {
        PIX *pix = pixRead(argv[1]);// считываем картинку из файла с именем,
        // переданным первым аргументом, это функционал Leptonica
        tessApi.SetImage(pix);// говорим tesseract, что распознавать нужно эту картинку
        char *text = tessApi.GetUTF8Text();//распознаём
        //---генерируем имя файла в который будет записан распознанный текст
        char *fileName = NULL;
        long prefixLength;
        const char* lastDotPosition = strrchr(argv[1], '.');
        if(lastDotPosition != NULL) {
            prefixLength = lastDotPosition - argv[1];
            fileName = new char[prefixLength + 5];
            strncpy(fileName, argv[1], prefixLength);
            strcpy(fileName + prefixLength, ".txt\0");
        } else {
            exit(1);
        }
        //---
        FILE *outF = fopen(fileName, "w");
        fprintf(outF, "%s", text);
        fclose(outF);
        //---
        pixDestroy(&pix);
        delete [] fileName;
        delete [] text;
    }
    return 0;
}

Собрать наше приложение можно командой:
g++ -O2 test.cpp -o test.exe -ltesseract_api -ltesseract_main -ltesseract_textord -ltesseract_wordrec -ltesseract_ccstruct -ltesseract_ccutil -ltesseract_classify -ltesseract_dict -ltesseract_image -ltesseract_viewer -ltesseract_cutil -ltesseract_cube -ltesseract_neural -llept -lws2_32
Линковка статическая, так как текущая версия tesseract не поддерживает создание DLL.

Заключение


По своему опыту знаю, что сложнее всего начать, поэтому надеюсь, что мой рассказ будет кому-нибудь полезен, особенно учитывая, что документации по Tesseract в сети преступно мало и основную, пожалуй, можно вытянуть из самих исходников с помощью doxygen.
PS: некоторые идеи для фиксов были почерпнуты в этом посте за что автору огромное спасибо.
Tags:
Hubs:
Total votes 22: ↑22 and ↓0+22
Comments13

Articles