traitement d'image pour améliorer tesseract OCR précision

J'ai utilisé tesseract pour convertir des documents en texte. La qualité des documents varie énormément, et je cherche des conseils sur le type de traitement d'image qui pourrait améliorer les résultats. J'ai remarqué que le texte hautement pixellisé - par exemple celui généré par les télécopieurs - est particulièrement difficile à traiter pour tesseract-probablement tous ces bords dentelés aux caractères confondent les algorithmes de reconnaissance de forme.

Quel genre de techniques de traitement d'image améliorer la précision? J'ai utilisé un flou gaussien pour lisser les images pixellisées et j'ai vu une petite amélioration, mais j'espère qu'il existe une technique plus spécifique qui donnerait de meilleurs résultats. Disons un filtre qui a été accordé aux images en noir et blanc, ce qui lisserait les bords irréguliers, suivi d'un filtre qui augmenterait le contraste pour rendre les caractères plus distincts.

Des conseils généraux pour quelqu'un qui est un novice en traitement d'image?

110
demandé sur JAL 2012-02-28 14:12:06

12 réponses

  1. fix DPI (si nécessaire) 300 DPI est minimum
  2. fixer la taille du texte (par exemple, 12 pt devrait être ok)
  3. Essayez de corriger les lignes de texte (deskew et dewarp text)
  4. essayer de corriger l'éclairage de l'image (par exemple, aucune partie sombre de l'image)
  5. binariser et de-bruit image

Il N'y a pas de ligne de commande universelle qui conviendrait à tous les cas (parfois, vous devez flouter et affiner l'image). Mais vous pouvez essayer TEXTCLEANER à partir des Scripts ImageMagick de Fred.

Si vous n'êtes pas fan de la ligne de commande, peut-être vous pouvez essayer d'utiliser opensource scantailor.sourceforge.net ou commerciales bookrestorer.

73
répondu user898678 2018-04-20 09:51:15

Je ne suis en aucun cas un expert OCR. Mais cette semaine, j'avais besoin de convertir du texte à partir d'un jpg.

J'ai commencé avec un colorisé, RVB 445x747 Pixel jpg. J'ai immédiatement essayé tesseract à ce sujet, et le programme converti presque rien. Je suis ensuite allé dans GIMP et a fait ce qui suit. image>mode>niveaux de gris image > image à l'échelle > 1191x2000 pixels filtres > améliorer > masque flou avec des valeurs de rayon = 6.8, montant = 2.69, seuil = 0 J'ai ensuite enregistré en tant que nouveau jpg à 100% de qualité.

Tesseract alors a été en mesure d'extraire tout le texte dans un .fichier txt

Gimp est ton ami.

63
répondu John 2012-07-24 18:45:55

Trois points pour améliorer la lisibilité de l'image: 1) redimensionner l'image avec une hauteur et une largeur variables (multiplier 0,5 et 1 et 2 avec la hauteur et la largeur de l'image). 2) convertir l'image au format D'échelle de gris (noir et blanc). 3) supprimer le bruit pixels et faire plus clair(filtre l'image).

Référez-vous au-dessous du 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;
        }

IMAGE D'ENTRÉE
L'IMAGE D'ENTRÉE

IMAGE DE SORTIE L'IMAGE DE SORTIE

26
répondu Sathyaraj Palanisamy 2016-12-15 00:34:37

C'est il y a un peu mais cela pourrait toujours être utile.

Mon expérience montre que le redimensionnement de l'image en mémoire avant de la transmettre à tesseract aide parfois.

Essayez différents modes d'interpolation. Le poste https://stackoverflow.com/a/4756906/146003 m'a beaucoup aidé.

16
répondu Atmocreations 2017-05-23 12:26:32

Ce qui m'a été extrêmement utile de cette façon, ce sont les codes source du projet Capture2Text. http://sourceforge.net/projects/capture2text/files/Capture2Text/.

BTW: Bravo à son auteur pour avoir partagé un algorithme aussi minutieux.

Portez une attention particulière au fichier Capture2Text\SourceCode\leptonica_util\leptonica_util.c-c'est l'essence de la préprocession d'image pour cet utilitaire.

Si vous exécutez les binaires, vous pouvez vérifier la transformation de l'image avant / après le processus dans Capture2Text \ output \ folder.

PS la solution mentionnée utilise Tesseract pour OCR et Leptonica pour le prétraitement.

13
répondu Wiseman 2014-03-21 12:13:00

Version Java pour le code de Sathyaraj ci-dessus:

// 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
répondu Fábio Silva 2016-07-20 01:37:59

Le seuillage adaptatif est important si l'éclairage est inégal sur l'image. Mon prétraitement utilisant GraphicsMagic est mentionné dans ce post: https://groups.google.com/forum/#! topic / Tesseract-ocr / jONGSChLRv4

GraphicsMagic a également la fonction-lat pour le seuil adaptatif linéaire du temps que je vais essayer bientôt.

Une autre méthode de seuillage utilisant OpenCV est décrite ici: http://docs.opencv.org/trunk/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.html

6
répondu rleir 2015-01-16 21:35:52

La documentation Tesseract contient quelques bons détails sur Comment améliorer la qualité OCR via les étapes de traitement d'image.

Dans une certaine mesure, Tesseract les applique automatiquement. Il est également possible de dire à Tesseract d'écrire une image intermédiaire pour inspection, c'est-à-dire de vérifier le bon fonctionnement du traitement d'image interne (recherchez tessedit_write_images dans la référence ci-dessus).

Plus important encore, le nouveau système de réseau neuronal {[5] } dans Tesseract 4 donne beaucoup mieux OCR résultats - en général et surtout pour les images avec un peu de bruit. Il est activé avec --oem 1, par exemple, comme dans:

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

(cet exemple sélectionne la langue allemande)

Ainsi, il est logique de tester d'abord jusqu'où vous obtenez avec le nouveau mode Tesseract LSTM avant d'appliquer certaines étapes de traitement d'image de prétraitement personnalisé.

(à la fin de 2017, Tesseract 4 n'est pas encore sorti aussi stable, mais la version de développement est utilisable)

5
répondu maxschlepzig 2018-03-22 09:45:46

En règle générale, j'applique généralement les techniques de prétraitement d'image suivantes en utilisant la bibliothèque OpenCV:

  1. Redimensionner l'image (c'est recommandé si vous travaillez avec des images dont le DPI est inférieur à 300 dpi):

    img = cv2.resize(img, None, fx=1.2, fy=1.2, interpolation=cv2.INTER_CUBIC)
    
  2. Conversion de l'image en niveaux de gris:

    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
  3. Appliquer la dilatation et l'érosion pour supprimer le bruit (vous pouvez jouer avec la taille du noyau en fonction de votre jeu de données):

    kernel = np.ones((1, 1), np.uint8)
    img = cv2.dilate(img, kernel, iterations=1)
    img = cv2.erode(img, kernel, iterations=1)
    
  4. Appliquer le flou, qui peut être fait en utilisant l'une des lignes suivantes (dont chacune a ses avantages et ses inconvénients, cependant, le flou médian et le filtre bilatéral fonctionnent généralement mieux que le flou gaussien.):

    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)
    

J'ai récemment écrit un guide assez simple pour Tesseract mais il devrait vous permettre d'écrire votre premier script OCR et de lever certains obstacles que j'ai rencontrés quand les choses étaient moins claires que je l'aurais souhaité dans la documentation.

Au cas où vous voudriez les vérifier, me voici partager les liens avec vous:

5
répondu bkaankuguoglu 2018-06-11 07:46:14

Je l'ai fait pour obtenir de bons résultats sur une image qui n'a pas de très petit texte.

  1. Appliquer le flou à l'image d'origine.
  2. Appliquer Un Seuil Adaptatif.
  3. Appliquer L'effet D'affûtage.

Et si le toujours pas obtenir de bons résultats, l'échelle de l'image à 150% ou 200%.

2
répondu Hamza Iqbal 2017-10-11 20:14:03

Lecture de texte à partir de documents d'image en utilisant un moteur OCR ont de nombreux problèmes afin d'obtenir une bonne précision. Il n'y a pas de solution fixe à tous les cas, mais voici quelques choses qui devraient être considérées pour améliorer les résultats OCR.

1) présence de bruit dû à une mauvaise qualité d'image / éléments indésirables / blobs dans la région d'arrière-plan. Cela nécessite des opérations de pré-traitement comme l'élimination du bruit qui peut être facilement fait en utilisant des méthodes de filtre gaussien ou de filtre médian normal. Ce sont aussi des disponible en OpenCV.

2) mauvaise orientation de l'image: en raison D'une mauvaise orientation, le moteur OCR ne parvient pas à segmenter correctement les lignes et les mots dans l'image, ce qui donne la pire précision.

3) présence de lignes: lors de la segmentation de mots ou de lignes, le moteur OCR essaie parfois de fusionner les mots et les lignes ensemble et de traiter ainsi le mauvais contenu et donc de donner de mauvais résultats. Il y a aussi d'autres problèmes, mais ce sont les problèmes de base.

Cet article OCR application est un exemple de cas où un pré-pré-traitement d'image et un post-traitement sur le résultat OCR peuvent être appliqués pour obtenir une meilleure précision OCR.

2
répondu flamelite 2017-10-23 10:11:58

La reconnaissance de texte dépend d'une variété de facteurs pour produire une sortie de bonne qualité. La sortie OCR dépend fortement de la qualité de l'image d'entrée. C'est pourquoi chaque moteur OCR fournit des directives concernant la qualité de l'image d'entrée et sa taille. Ces directives aident le moteur OCR à produire des résultats précis.

J'ai écrit un article détaillé sur le traitement d'image en python. Veuillez suivre le lien ci-dessous pour plus d'explications. A également ajouté le code source python pour les implémenter processus.

Veuillez écrire un commentaire si vous avez une suggestion ou une meilleure idée sur ce sujet pour l'améliorer.

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

1
répondu Brijesh Gupta 2018-09-18 06:43:22