OCR avec tesseract
Par Cédric Tabin le dimanche 11.09.2011, 15:00 - C/C++ - Lien permanent
Tesseract est une librairie permettant de faire de la reconnaissance de caractères dans une image (OCR). Ce billet est un petit tutorial pour utiliser la librairie en C++ sous linux gentoo. Pour avoir une idée du résultat, il y a l'excellent outil online free-ocr.
Pour ceux qui désirent juste utiliser l'outil tesseract fourni directement, voici un autre tutorial.
Prérequis
Pour faciliter le prétraitement des images, il est recommandé d'installer les librairies imagemagick (pour transformer les images dans différents formats) et tiff (pour manipuler le format tiff). Pour créer les fichiers de configuration automatiquement, j'utilise cmake plutôt que les autotools.
emerge -q tiff imagemagick cmake
Préparation
Pour plus de simplicité, la structure des fichiers sera la suivante:
tess-test - Dossier du projet tess-test/libs - Librairies (*.a) tess-test/tesseract-3.00 - Sources tesseract tess-test/CMakeLists.txt - Configuration CMake tess-test/main.cpp - Exemple d'utilisation
Pour créer la structure de base:
mkdir -p "tess-test/libs" cd "tess-test"
Installation de tesseract
La dernière version est la 3.0. Pour la télécharger et l'installer, simplement exécuter les commandes ci-dessous. Il existe une documentation plus complète ici.
wget "http://tesseract-ocr.googlecode.com/files/tesseract-3.00.tar.gz" tar -xf "tesseract-3.00.tar.gz" cd "tesseract-3.00" ./configure make -j3
Une fois compilé, les librairies tesseract sont éparpillées dans différents dossier. Pour plus de facilité, elles sont simplement copiées dans le répertoire libs.
find . -iname "*.a" -exec cp {} "../libs" \; cd ..
Fichier de configuration
Le fichier Makefile va être automatiquement créé par CMake. Voici le contenu du fichier CMakeLists.txt qui sera utilisé:
cmake_minimum_required (VERSION 2.6) project (Tesseract) add_definitions("-g") link_directories("./libs") include_directories("/usr/include/ImageMagick") include_directories("./tesseract-3.00/api") include_directories("./tesseract-3.00/ccstruct") include_directories("./tesseract-3.00/wordrec") include_directories("./tesseract-3.00/dict") include_directories("./tesseract-3.00/ccmain") include_directories("./tesseract-3.00/cutil") include_directories("./tesseract-3.00/ccutil") include_directories("./tesseract-3.00/textord") include_directories("./tesseract-3.00/classify") include_directories("./tesseract-3.00/image") include_directories("./tesseract-3.00/viewer") add_executable(tesstest main.cpp) # L'ordre des librairies est important !!! target_link_libraries (tesstest Magick++ tesseract_api tesseract_main tesseract_textord tesseract_wordrec tesseract_classify tesseract_dict tesseract_ccstruct tesseract_image tesseract_cutil tesseract_viewer tesseract_ccutil)
Programme
Le fichier main.cpp se constitue en trois parties (pour l'exemple, les vérifications d'usages sont omises). La première est la conversion d'une image au format TIFF (c'est le seul format 'compris' par tesseract).
int main(int argc, char* argv[]) { const char* file = "image.png"; const char* tifName = "test.tif"; // Conversion avec ImageMagick Magick::Image img; img.read(file); img.write(tifName); //... }
Ensuite, le fichier TIFF est ouvert et chargé en mémoire pour pouvoir être analysé.
int main(int argc, char* argv[]) { const char* file = "image.png"; const char* tifName = "test.tif"; // Conversion avec ImageMagick Magick::Image img; img.read(file); img.write(tifName); // Chargement de l'image en mémoire FILE* fp = fopen(tifName, "rb"); TIFF* archive = TIFFOpen(tifName, "r"); IMAGE image; read_tiff_image(archive, &image); TIFFClose(archive); fclose(fp); //... }
Et finalement, tesseract récupère les données depuis l'image en mémoire.
int main(int argc, char* argv[]) { const char* file = "image.png"; const char* tifName = "test.tif"; // Conversion avec ImageMagick Magick::Image img; img.read(file); img.write(tifName); // Chargement de l'image en mémoire FILE* fp = fopen(tifName, "rb"); TIFF* archive = TIFFOpen(tifName, "r"); IMAGE image; read_tiff_image(archive, &image); TIFFClose(archive); fclose(fp); // Utilisation de Tesseract TessBaseAPI* api = new TessBaseAPI(); api->Init(argv[0], "fra"); api->SetAccuracyVSpeed(AVS_MOST_ACCURATE); int bytes_per_line = check_legal_image_size(image.get_xsize(), image.get_ysize(), image.get_bpp()); api->SetImage(image.get_buffer(), image.get_xsize(), image.get_ysize(), image.get_bpp()/8, bytes_per_line); const char* text = api->GetUTF8Text(); printf("Text: %s\n", text); return 0; }
Compilation
Pour compiler, la première fois il faut demander à CMake de créer le fichier Makefile. Il suffit ensuite de lancer la commande usuelle make.
cmake .
make
Exécution
Pour que tesseract puisse reconnaître efficacement les caractères, un fichier de données doit lui être donné. Il en existe un pour la plupart des langues. Ce dernier doit être placé dans un dossier .tessdata.
mkdir ".tessdata" cd ".tessdata" wget "http://tesseract-ocr.googlecode.com/files/fra.traineddata.gz" gunzip "fra.traineddata.gz" cd ..
Pour tester le moteur, l'image suivante est utiisée (source):
Finalement, il ne reste plus qu'a indiquer le chemin vers le fichier des données et à exécuter le programme.
export TESSDATA_PREFIX="." ./tesstest
En annexe, vous trouverez un petit script en bash pour télécharger et compiler l'exemple ci-dessus.
Tips
Il faut faire attention au format de l'image. Idéalement pour que tesseract fonctionne bien (par exemple sur un scan d'une facture), il faudrait que l'image soit au format BMP avec une résolution à 300 dpi. Particulièrement, il faut se méfier du format JPG car la compression nuit fortement à la reconnaissance de caractères.
Toutefois, il existe un outil très pratique pour améliorer les performances de l'OCR sur des images compressées ou de mauvaise qualité: unpaper.
emerge -q unpaper netpbm
Voici un petit exemple d'utilisation (netpbm permet la conversion des fichiers dans un format compréhensible pour unpaper):
jpegtopnm "image.jpg" > "image.pnm" unpaper --zoom 1.5 -w 0.9 -b 0.5 --sheet-background white --dpi 500 "image.pnm" "image-unpaper.pnm" pnmtojpeg "image-unpaper.pnm" > "image-unpaper.jpg"
A noter également que le format TIFF permet de gérer plusieurs pages. Dans les sources de tesseract (ici), il est possible de voir comment les gérer.
Commentaires
Браво! Очень хороший пример!