Tag Archives: Schrifterkennung

Schrifterkennung in .NET mit Tesseract

Tesseract ist nicht nur der Name eines vier-dimensionalen Würfels in der Geometrie, sondern auch der Projektname einer OCR – Software . Hewlett-Packard entwickelte diese Schrifterkennungssoftware zwischen 1985 und 1995. Im Jahr 2005 übernahm Google die Software und veröffentlichte sie unter der Apache License 2.0 als Open-Source-Projekt. Seit 2006 wird Tesseract von Google weiterentwickelt. Tesseract ist eine cross-plattfrom C++ Bibliothek. Allerdings existieren für fast jede Umgebung entsprechende Wrapper-Projekte. Ein solcher Wrapper ist Tesseract für .NET von Charles Weld. Der Code ist als NuGet -Paket verfügbar und somit sehr einfach zu installieren. Um Tesseract in einen .NET Projekt zu verwenden muss nur das NuGet-Paket hinzugefügt werden. In Visual Studio genügt dazu ein rechts-Klick auf Verweise und dann auf NuGet-Pakete verwalten.

nuget

 

Gibt man “tesseract” als Suchbegriff bei der Online-Suche ein, erscheint als der .NET Wrapper von Charles Weld. Durch Klick auf Installieren wird das Paket dem Projekt hinzugefügt. Dabei werden die 64 und 32 bit Tesseract C++-Bibliotheken in einen entsprechenden Ordner, sowie die .NET Wrapper-Lib, dem Projekt automatisch hinzugefügt.

tesseract-nugetsearch

Damit eine Software Muster und Informationen in Bildern erkennen kann, muss sie “trainiert” werden. Dabei besitzen unterschiedliche Sprachen unterschiedliche Schriftzeichen. Manche Sprachen unterscheiden sich sogar in der Leserichting (rechts nach links). Ursprünglich unterstützte Tesseract nur englischen Wortschatz. Google hat die Software weiterentwickelt und unterstützt nun viele weitere Sprachen (u.a. deutsch, chinesisch, hebräisch…). Für jede dieser Sprachen gibt es Sprachdaten auf der Google-Code-Download-Seite von Tesseract. Da diese Daten im NuGet-Paket nicht enthalten sind müssen diese von der Google-Seite downloaden. Bei der initialisierung der OCR-Engine muss auf diese Daten verwiesen werden. Für dieses Beispielprogramm habe ich die englischen Sprachdaten heruntergeladen und entpackt. Um die Sprachdaten zum Projekt hinzuzufügen kann der tessdata-Ordner kopiert und mit STRG+V in Visual Studio zum Projekt hinzugefügt werden.

tessdata

 

Das waren alle nötigen Dateien und Verweise um Schrifterkennung mit Tesseract in .NET zu betreiben. Nun also zum Code. Um den OCR-Spezifischen Code vom Rest zu trennen wird zunächst eine Schnittstelle definiert. Die Implementierung dieser Schnittstelle muss eine Methode zur Verfügung stellen, die sämtlichen Text aus einem Bitmap Objekt ausliest und zurückgibt.

namespace Blog.TesseractOcr.OCR
{
    interface IOCRService
    {
        string GetTextFromBitmap(System.Drawing.Bitmap bmp);
    }
}

Die TesseractOcrService Klasse implementiert diese Schnittstelle mit Hilfe des Tesseract .NET Wrappers von Charles Weld.

namespace Blog.TesseractOcr.OCR
{
    class TesseractOcrService : IOcrService
    {
        
        private readonly TesseractEngine mOcrEngine;
        private static readonly string DATA_PATH = "";
        private static readonly string LANGUAGE = "en";

        public TesseractOcrService()
        {
            mOcrEngine = new TesseractEngine(DATA_PATH, LANGUAGE, EngineMode.Default);
        }

        public string GetTextFromBitmap(System.Drawing.Bitmap bmp)
        {
            string result = String.Empty;

            using (Page page = mOcrEngine.Process(bmp))
            {
                result = page.GetText();
            }
            
            return result;
        }
    }
}

Nun aber zum Beispielprogramm. Zum Testen der OCR-Bibliothek bzw. der obigen Schnittstelle habe ich eine kleine GUI-Anwendung geschrieben, die es ermöglicht eine Bilddatei auszuwählen. Nach dem Laden des Bildes wird es angezeigt und an den OCR Service weitergereicht um nach enthaltenen Text zu suchen. Falls die Tesseract-OCR-Engine Zeichen findet werden diese in einen Textfeld neben dem Bild angezeigt. Bei dem Programm handelt es sich um eine WPF Anwendung die, um den Code-Umfang gering zu halten, auf eine kleine WPF/MVVM-Bibliothek zurückgreift. Die ganze Logik des Programms befindet sich in der MainVM-Klasse, die als Viewmodel des Hauptfensters dient:

using Blog.TesseractOcr.OCR;
using RS.WPF.Framework;
using RS.WPF.Framework.Dialog;
using System;
using System.Drawing;

namespace Blog.TesseractOcr.ViewModel
{
    class MainVM : ViewModelBase
    {

        private readonly IOcrService mOCRService;
        private readonly IFileDialogService mFileDialogService;
        private readonly BindableCommand mOpenImgCmd;

        private Bitmap mImage;
        private string mText;

        public MainVM()
        {
            mOCRService = new TesseractOcrService();
            mFileDialogService = new FileDialogService();
            mOpenImgCmd = new BindableCommand(OnOpenImageBtnClick);
        }

        private void OnOpenImageBtnClick()
        {
           string file = mFileDialogService.OpenFileDialog(null,
               new string[] { ".bmp", ".jpg" });
           if (file == String.Empty)
               return;
           LoadImage(file);
        }

        private void LoadImage(string file)
        {
           mImage = new Bitmap(file);
           RaisePropertyChanged(() => Image); // Dem View mitteilen dass sich das Bild geändert hat
           ProcessImage();
        }

  
        private void ProcessImage()
        {
           mText = mOCRService.GetTextFromBitmap(mImage);
           RaisePropertyChanged(() => Text); // Dem View mitteilen dass sich der Text geändert hat
        }


        /*
         *      PROPERTIES
         */
        public BindableCommand OpenImgCmd
        {
            get { return mOpenImgCmd; }
        }

        public Bitmap Image
        {
            get { return mImage; }
        }

        public string Text
        {
            get { return mText; }
            set { mText = value; }
        }
    }
}

Die Oberfläche wird in Mainwindow.xaml wie folgt definiert:

<Window x:Class="Blog.TesseractOcr.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:Blog.TesseractOcr.ViewModel"
        xmlns:converter="clr-namespace:RS.WPF.Framework.Util;assembly=RS.WPF.Framework"
        Title="Schrifterkennung mit Tesseract OCR"
        Height="550"
        Width="755">
    <!-- MainVM als Kontext setzen -->
    <Window.DataContext>
        <vm:MainVM />
    </Window.DataContext>
    <!-- Bitmap zu ImageSource Converter-->
    <Window.Resources>
        <converter:BitmapToImageSourceConverter x:Key="bmpToImgSrc" />
    </Window.Resources>
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="10" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="10" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="5" />
            <RowDefinition Height="*" />
            <RowDefinition Height="10" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="10" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="10" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="10" />
        </Grid.ColumnDefinitions>
        <!-- Bild öffnen Button-->
        <Button Grid.Column="1"
                Grid.Row="1"
                Width="100"
                Command="{Binding OpenImgCmd}"
                Content="Bild öffnen" 
                HorizontalAlignment="Left"/>
        <!-- Geladenes Bild anzeigen -->
        <TextBlock Grid.Column="1"
                   Grid.Row="3"
                   Text="Bild:" />          
        <Image Grid.Column="1"
               Grid.Row="5"
               Source="{Binding Image, Converter={StaticResource bmpToImgSrc}}" />    
        <Border  Grid.Column="1"
                 Grid.Row="5"
                 BorderBrush="Black"
                 BorderThickness=".5" />
        <!-- Gefundener Text -->
        <TextBlock Grid.Column="3"
                   Grid.Row="3"
                   Text="Gefundener Text:" />
        <TextBox  Grid.Column="3"
                  Grid.Row="5"
                  FontSize="16"
                  Text="{Binding Text}" />
        
    </Grid>
</Window>

Das ganze Visual Studio Projekt ist auf GitHub unter folgenden Link verfügbar: https://github.com/robibobi/blog-tesseract-dotnet-example.

Folgender Screenshot zeigt das Programm bei der Ausführung:

Beispiel2

 

Quellen und Links:

https://github.com/tesseract-ocr

http://googlecode.blogspot.de/2006/08/announcing-tesseract-ocr.html