it-swarm.com.de

bildverarbeitung zur Verbesserung der OCR-Genauigkeit

Ich habe Tesseract verwendet, um Dokumente in Text umzuwandeln. Die Qualität der Dokumente ist enorm und ich suche nach Tipps, welche Art von Bildverarbeitung die Ergebnisse verbessern könnte. Ich habe festgestellt, dass hochpixellierter Text - zum Beispiel der von Faxgeräten - besonders schwer zu verarbeiten ist - vermutlich alle diese gezackten Kanten der Zeichen verwechseln die Formerkennungsalgorithmen. 

Welche Bildverarbeitungstechniken würden die Genauigkeit verbessern? Ich habe eine Gaußsche Unschärfe verwendet, um die pixelierten Bilder zu glätten, und habe eine kleine Verbesserung gesehen, aber ich hoffe, dass es eine spezifischere Technik gibt, die bessere Ergebnisse liefert. Sagen Sie einen Filter, der auf Schwarz-Weiß-Bilder abgestimmt ist, wodurch unregelmäßige Kanten geglättet werden, gefolgt von einem Filter, der den Kontrast erhöht, um die Zeichen deutlicher zu machen.

Irgendwelche allgemeinen Tipps für jemanden, der Anfänger bei der Bildverarbeitung ist? 

114
user364902
  1. fixe DPI (falls erforderlich) mindestens 300 DPI
  2. textgröße fixieren (z. B. sollte 12 pt in Ordnung sein)
  3. versuchen, Textzeilen zu korrigieren (Deskew- und Dewarp-Text)
  4. versuchen, die Beleuchtung des Bildes zu korrigieren (z. B. kein dunkler Teil des Bildes)
  5. binärbild und Rauschbild

Es gibt keine universelle Befehlszeile, die für alle Fälle geeignet wäre (manchmal müssen Sie das Bild unscharf machen und das Bild schärfen). Aber Sie können es mit TEXTCLEANER aus Fred's ImageMagick-Skripten versuchen.

Wenn Sie kein Fan der Befehlszeile sind, können Sie vielleicht versuchen, opensource scantailor.sourceforge.net oder commercial bookrestorer zu verwenden.

79
user898678

Ich bin kein OCR-Experte. Aber ich musste diese Woche Text aus einem jpg konvertieren.

Ich habe mit einem kolorierten RGB-Pixel mit 445x747 Pixeln begonnen. Ich habe sofort tesseract versucht, und das Programm hat fast nichts konvertiert. __ Ich ging dann in GIMP und tat Folgendes Image> mode> Graustufen Image> Bild skalieren> 1191x2000 Pixel Filter> verbessern> unscharfe Maske mit Werten von Radius = 6,8, Betrag = 2,69, Schwellwert = 0 .__ Ich habe dann ein neues JPG mit 100% Qualität gespeichert.

Tesseract konnte dann den gesamten Text in eine TXT-Datei extrahieren

Gimp ist dein Freund.

65
John

Drei Punkte zur Verbesserung der Lesbarkeit des Bildes: 1) Ändern Sie die Größe des Bildes mit variabler Höhe und Breite (multiplizieren Sie 0,5 und 1 und 2 mit Bildhöhe und -breite) . 2) Konvertieren Sie das Bild in das Graustufenformat ( Schwarzweiß) ..__ 3) Entfernen Sie die Rauschpixel und machen Sie deutlicher (Filtern Sie das Bild).

Siehe untenstehenden Code: 

//Resize
  public Bitmap Resize(Bitmap bmp, int newWidth, int newHeight)
        {

                Bitmap temp = (Bitmap)bmp;

                Bitmap bmap = new Bitmap(newWidth, newHeight, temp.PixelFormat);

                double nWidthFactor = (double)temp.Width / (double)newWidth;
                double nHeightFactor = (double)temp.Height / (double)newHeight;

                double fx, fy, nx, ny;
                int cx, cy, fr_x, fr_y;
                Color color1 = new Color();
                Color color2 = new Color();
                Color color3 = new Color();
                Color color4 = new Color();
                byte nRed, nGreen, nBlue;

                byte bp1, bp2;

                for (int x = 0; x < bmap.Width; ++x)
                {
                    for (int y = 0; y < bmap.Height; ++y)
                    {

                        fr_x = (int)Math.Floor(x * nWidthFactor);
                        fr_y = (int)Math.Floor(y * nHeightFactor);
                        cx = fr_x + 1;
                        if (cx >= temp.Width) cx = fr_x;
                        cy = fr_y + 1;
                        if (cy >= temp.Height) cy = fr_y;
                        fx = x * nWidthFactor - fr_x;
                        fy = y * nHeightFactor - fr_y;
                        nx = 1.0 - fx;
                        ny = 1.0 - fy;

                        color1 = temp.GetPixel(fr_x, fr_y);
                        color2 = temp.GetPixel(cx, fr_y);
                        color3 = temp.GetPixel(fr_x, cy);
                        color4 = temp.GetPixel(cx, cy);

                        // Blue
                        bp1 = (byte)(nx * color1.B + fx * color2.B);

                        bp2 = (byte)(nx * color3.B + fx * color4.B);

                        nBlue = (byte)(ny * (double)(bp1) + fy * (double)(bp2));

                        // Green
                        bp1 = (byte)(nx * color1.G + fx * color2.G);

                        bp2 = (byte)(nx * color3.G + fx * color4.G);

                        nGreen = (byte)(ny * (double)(bp1) + fy * (double)(bp2));

                        // Red
                        bp1 = (byte)(nx * color1.R + fx * color2.R);

                        bp2 = (byte)(nx * color3.R + fx * color4.R);

                        nRed = (byte)(ny * (double)(bp1) + fy * (double)(bp2));

                        bmap.SetPixel(x, y, System.Drawing.Color.FromArgb
                (255, nRed, nGreen, nBlue));
                    }
                }



                bmap = SetGrayscale(bmap);
                bmap = RemoveNoise(bmap);

                return bmap;

        }


//SetGrayscale
  public Bitmap SetGrayscale(Bitmap img)
        {

            Bitmap temp = (Bitmap)img;
            Bitmap bmap = (Bitmap)temp.Clone();
            Color c;
            for (int i = 0; i < bmap.Width; i++)
            {
                for (int j = 0; j < bmap.Height; j++)
                {
                    c = bmap.GetPixel(i, j);
                    byte gray = (byte)(.299 * c.R + .587 * c.G + .114 * c.B);

                    bmap.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
                }
            }
            return (Bitmap)bmap.Clone();

        }
//RemoveNoise
   public Bitmap RemoveNoise(Bitmap bmap)
        {

            for (var x = 0; x < bmap.Width; x++)
            {
                for (var y = 0; y < bmap.Height; y++)
                {
                    var pixel = bmap.GetPixel(x, y);
                    if (pixel.R < 162 && pixel.G < 162 && pixel.B < 162)
                        bmap.SetPixel(x, y, Color.Black);
                    else if (pixel.R > 162 && pixel.G > 162 && pixel.B > 162)
                        bmap.SetPixel(x, y, Color.White);
                }
            }

            return bmap;
        }

INPUT-BILD
INPUT IMAGE

AUSGABEBILD OUTPUT IMAGE

28

Dies ist vor einiger Zeit, kann aber dennoch nützlich sein.

Meine Erfahrung zeigt, dass es manchmal hilfreich ist, das Bild im Speicher zu ändern, bevor es an Tesseract übergeben wird.

Probieren Sie verschiedene Interpolationsmodi aus. Der Beitrag https://stackoverflow.com/a/4756906/146003 hat mir sehr geholfen.

16
Atmocreations

Was auf diesem Weg EXTREM HILFREICH war, sind die Quellcodes für das Capture2Text-Projekt . http://sourceforge.net/projects/capture2text/files/Capture2Text/ .

Übrigens: Ein Lob an den Autor, einen solch mühsamen Algorithmus zu teilen.

Achten Sie besonders auf die Datei Capture2Text\SourceCode\leptonica_util\leptonica_util.c. Dies ist die Essenz des Image-Preprozesses für dieses Dienstprogramm.

Wenn Sie die Binärdateien ausführen, können Sie die Bildumwandlung vor/nach dem Vorgang im Ordner Capture2Text\Output\überprüfen.

P.S. Die erwähnte Lösung verwendet Tesseract für OCR und Leptonica für die Vorverarbeitung.

13
Wiseman

Java-Version für Sathyaraj-Code oben:

// Resize
public Bitmap resize(Bitmap img, int newWidth, int newHeight) {
    Bitmap bmap = img.copy(img.getConfig(), true);

    double nWidthFactor = (double) img.getWidth() / (double) newWidth;
    double nHeightFactor = (double) img.getHeight() / (double) newHeight;

    double fx, fy, nx, ny;
    int cx, cy, fr_x, fr_y;
    int color1;
    int color2;
    int color3;
    int color4;
    byte nRed, nGreen, nBlue;

    byte bp1, bp2;

    for (int x = 0; x < bmap.getWidth(); ++x) {
        for (int y = 0; y < bmap.getHeight(); ++y) {

            fr_x = (int) Math.floor(x * nWidthFactor);
            fr_y = (int) Math.floor(y * nHeightFactor);
            cx = fr_x + 1;
            if (cx >= img.getWidth())
                cx = fr_x;
            cy = fr_y + 1;
            if (cy >= img.getHeight())
                cy = fr_y;
            fx = x * nWidthFactor - fr_x;
            fy = y * nHeightFactor - fr_y;
            nx = 1.0 - fx;
            ny = 1.0 - fy;

            color1 = img.getPixel(fr_x, fr_y);
            color2 = img.getPixel(cx, fr_y);
            color3 = img.getPixel(fr_x, cy);
            color4 = img.getPixel(cx, cy);

            // Blue
            bp1 = (byte) (nx * Color.blue(color1) + fx * Color.blue(color2));
            bp2 = (byte) (nx * Color.blue(color3) + fx * Color.blue(color4));
            nBlue = (byte) (ny * (double) (bp1) + fy * (double) (bp2));

            // Green
            bp1 = (byte) (nx * Color.green(color1) + fx * Color.green(color2));
            bp2 = (byte) (nx * Color.green(color3) + fx * Color.green(color4));
            nGreen = (byte) (ny * (double) (bp1) + fy * (double) (bp2));

            // Red
            bp1 = (byte) (nx * Color.red(color1) + fx * Color.red(color2));
            bp2 = (byte) (nx * Color.red(color3) + fx * Color.red(color4));
            nRed = (byte) (ny * (double) (bp1) + fy * (double) (bp2));

            bmap.setPixel(x, y, Color.argb(255, nRed, nGreen, nBlue));
        }
    }

    bmap = setGrayscale(bmap);
    bmap = removeNoise(bmap);

    return bmap;
}

// SetGrayscale
private Bitmap setGrayscale(Bitmap img) {
    Bitmap bmap = img.copy(img.getConfig(), true);
    int c;
    for (int i = 0; i < bmap.getWidth(); i++) {
        for (int j = 0; j < bmap.getHeight(); j++) {
            c = bmap.getPixel(i, j);
            byte gray = (byte) (.299 * Color.red(c) + .587 * Color.green(c)
                    + .114 * Color.blue(c));

            bmap.setPixel(i, j, Color.argb(255, gray, gray, gray));
        }
    }
    return bmap;
}

// RemoveNoise
private Bitmap removeNoise(Bitmap bmap) {
    for (int x = 0; x < bmap.getWidth(); x++) {
        for (int y = 0; y < bmap.getHeight(); y++) {
            int pixel = bmap.getPixel(x, y);
            if (Color.red(pixel) < 162 && Color.green(pixel) < 162 && Color.blue(pixel) < 162) {
                bmap.setPixel(x, y, Color.BLACK);
            }
        }
    }
    for (int x = 0; x < bmap.getWidth(); x++) {
        for (int y = 0; y < bmap.getHeight(); y++) {
            int pixel = bmap.getPixel(x, y);
            if (Color.red(pixel) > 162 && Color.green(pixel) > 162 && Color.blue(pixel) > 162) {
                bmap.setPixel(x, y, Color.WHITE);
            }
        }
    }
    return bmap;
}
12
Fábio Silva

Als Faustregel wende ich normalerweise die folgenden Bildvorverarbeitungstechniken mit der OpenCV-Bibliothek an:

  1. Neuskalierung des Bildes (wird empfohlen, wenn Sie mit Bildern arbeiten, deren DPI-Wert weniger als 300 dpi beträgt):

    img = cv2.resize(img, None, fx=1.2, fy=1.2, interpolation=cv2.INTER_CUBIC)
    
  2. Bild in Graustufen konvertieren:

    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
  3. Anwenden von Dilatation und Erosion, um das Rauschen zu entfernen (abhängig von Ihrem Datensatz können Sie mit der Kerngröße spielen):

    kernel = np.ones((1, 1), np.uint8)
    img = cv2.dilate(img, kernel, iterations=1)
    img = cv2.erode(img, kernel, iterations=1)
    
  4. Das Anwenden von Unschärfe, das durch Verwenden einer der folgenden Zeilen erfolgen kann (von denen jede ihre Vor- und Nachteile hat, jedoch erzielen Median Unschärfe und bilateraler Filter normalerweise eine bessere Leistung als Gaußsche Unschärfe.):

    cv2.threshold(cv2.GaussianBlur(img, (5, 5), 0), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    cv2.threshold(cv2.bilateralFilter(img, 5, 75, 75), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    cv2.threshold(cv2.medianBlur(img, 3), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    cv2.adaptiveThreshold(cv2.GaussianBlur(img, (5, 5), 0), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
    
    cv2.adaptiveThreshold(cv2.bilateralFilter(img, 9, 75, 75), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
    
    cv2.adaptiveThreshold(cv2.medianBlur(img, 3), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
    

Ich habe vor kurzem einen ziemlich einfachen Leitfaden für Tesseract geschrieben, aber er sollte es Ihnen ermöglichen, Ihr erstes OCR-Skript zu schreiben und einige Hürden zu beseitigen, die ich erlebt habe, wenn die Dinge weniger klar waren, als ich es in der Dokumentation gewünscht hätte.

Wenn Sie sie auschecken möchten, teile ich Ihnen hier die Links:

9
bkaankuguoglu

Adaptives Thresholding ist wichtig, wenn die Beleuchtung im gesamten Bild uneinheitlich ist . In diesem Beitrag wird auf meine Vorverarbeitung mit GraphicsMagic hingewiesen: https://groups.google.com/forum/#!topic/tesseract-ocr/jONGSChLRv4

GraphicsMagic hat auch die -lat-Funktion für den adaptiven Grenzwert der linearen Zeit, die ich bald ausprobieren werde.

Eine andere Methode des Thresholding mit OpenCV wird hier beschrieben: http://docs.opencv.org/trunk/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.html

6
rleir

Die Tesseract-Dokumentation enthält einige gute Details zu Verbesserung der OCR-Qualität über Bildverarbeitungsschritte.

Tesseract wendet sie bis zu einem gewissen Grad automatisch an. Es ist auch möglich, Tesseract mitzuteilen, ein Zwischenbild zur Prüfung zu schreiben, d. H. Zu überprüfen, wie gut die interne Bildverarbeitung funktioniert (Suche nach tessedit_write_images in der obigen Referenz).

Noch wichtiger ist, dass das New Neural Network System in Tesseract 4 wesentlich bessere OCR-Ergebnisse liefert - im Allgemeinen und insbesondere für Bilder mit etwas Rauschen. Es wird mit --oem 1 aktiviert, z. wie in:

$ tesseract --oem 1 -l deu page.png result pdf

(dieses Beispiel wählt die deutsche Sprache)

Daher ist es sinnvoll, zunächst zu testen, wie weit Sie mit dem neuen Tesseract LSTM-Modus gelangen, bevor Sie einige benutzerdefinierte Bildverarbeitungsschritte vorverarbeiten.

(Ende 2017 ist Tesseract 4 noch nicht als stabil veröffentlicht, aber die Entwicklungsversion ist verwendbar.)

5
maxschlepzig

Das Lesen von Text aus Bilddokumenten mit einer beliebigen OCR-Engine hat viele Probleme, um eine gute Genauigkeit zu erreichen. Es gibt keine feste Lösung für alle Fälle, aber es gibt einige Dinge, die zur Verbesserung der OCR-Ergebnisse in Betracht gezogen werden sollten.

1) Vorhandensein von Rauschen aufgrund schlechter Bildqualität/unerwünschter Elemente/Flecken im Hintergrundbereich. Dies erfordert einige Vorverarbeitungsvorgänge wie die Rauschentfernung, die leicht mit einem Gaußschen Filter oder normalen Medianfilterverfahren durchgeführt werden kann. Diese sind auch in OpenCV verfügbar.

2) Falsche Ausrichtung des Bildes: Aufgrund einer falschen Ausrichtung kann die OCR-Engine die Zeilen und Wörter im Bild nicht richtig segmentieren, was die schlechteste Genauigkeit ergibt.

3) Vorhandensein von Zeilen: Während der Wort- oder Liniensegmentierung versucht die OCR-Engine manchmal auch, die Wörter und Zeilen zusammenzuführen, um so falschen Inhalt zu verarbeiten und falsche Ergebnisse zu liefern. Es gibt auch andere Probleme, aber dies sind die grundlegenden.

Diese Post OCR-Anwendung ist ein Beispiel, in dem einige Bildvorverarbeitung und Nachbearbeitung des OCR-Ergebnisses angewendet werden können, um eine bessere OCR-Genauigkeit zu erzielen.

2
flamelite

Ich habe dies getan, um gute Ergebnisse mit einem Bild zu erzielen, das nicht sehr kleinen Text hat.

  1. Wenden Sie Unschärfe auf das Originalbild an.
  2. Übernehmen Sie den adaptiven Schwellenwert.
  3. Wenden Sie den Schärfeffekt an.

Wenn das Ergebnis immer noch nicht gut ist, skalieren Sie das Bild auf 150% oder 200%.

2
Hamza Iqbal

Die Texterkennung hängt von einer Vielzahl von Faktoren ab, um eine gute Ausgabequalität zu erzielen. Die OCR-Ausgabe hängt stark von der Qualität des Eingabebildes ab. Aus diesem Grund bietet jedes OCR-Modul Richtlinien zur Qualität des Eingabebildes und seiner Größe. Diese Richtlinien helfen der OCR-Engine, genaue Ergebnisse zu erzielen.

Ich habe einen ausführlichen Artikel zur Bildverarbeitung in Python geschrieben. Folgen Sie bitte dem Link unten, um weitere Informationen zu erhalten. Außerdem wurde der Python-Quellcode hinzugefügt, um diesen Prozess zu implementieren.

Bitte schreiben Sie einen Kommentar, wenn Sie einen Vorschlag oder eine bessere Idee zu diesem Thema haben, um ihn zu verbessern.

https://medium.com/cashify-engineering/improve-accuracy-of-ocr-using-image-preprocessing-8df29ec3a033

0
Brijesh Gupta