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?
12 réponses
- fix DPI (si nécessaire) 300 DPI est minimum
- fixer la taille du texte (par exemple, 12 pt devrait être ok)
- Essayez de corriger les lignes de texte (deskew et dewarp text)
- essayer de corriger l'éclairage de l'image (par exemple, aucune partie sombre de l'image)
- 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.
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.
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
IMAGE DE SORTIE
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é.
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.
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;
}
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
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)
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:
-
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)
-
Conversion de l'image en niveaux de gris:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
-
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)
-
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:
Je l'ai fait pour obtenir de bons résultats sur une image qui n'a pas de très petit texte.
- Appliquer le flou à l'image d'origine.
- Appliquer Un Seuil Adaptatif.
- Appliquer L'effet D'affûtage.
Et si le toujours pas obtenir de bons résultats, l'échelle de l'image à 150% ou 200%.
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.
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.