web-dev-qa-db-fra.com

Image de prétraitement pour Tesseract OCR avec OpenCV

J'essaie de développer une application qui utilise Tesseract pour reconnaître le texte des documents pris par la caméra d'un téléphone. J'utilise OpenCV pour prétraiter l'image pour une meilleure reconnaissance, en appliquant un flou gaussien et une méthode de seuil pour la binarisation, mais le résultat est assez mauvais.

Ici est l'image que j'utilise pour les tests: enter image description here

Et ici l'image prétraitée: enter image description here

Quels autres filtres puis-je utiliser pour rendre l'image plus lisible pour Tesseract?

22
Mauricio

J'ai décrit quelques conseils pour préparer des images pour Tesseract ici: tilisation de tesseract pour reconnaître les plaques d'immatriculation

Dans votre exemple, il se passe plusieurs choses ...

Vous devez obtenir le texte en noir et le reste de l'image en blanc ( pas l'inverse). C'est sur cela que la reconnaissance des caractères est réglée. Les niveaux de gris sont ok, tant que l'arrière-plan est principalement blanc et le texte est entièrement noir; les bords du texte peuvent être gris (anti-crénelés) et cela peut aider à la reconnaissance (mais pas nécessairement - vous devrez expérimenter)

L'un des problèmes que vous voyez est que dans certaines parties de l'image, le texte est vraiment "fin" (et des lacunes dans les lettres apparaissent après le seuillage), tandis que dans d'autres parties, il est vraiment "épais" (et les lettres commencent fusion). Tesseract n'aimera pas ça :) Cela se produit parce que l'image d'entrée n'est pas uniformément éclairée, donc un seul seuil ne fonctionne pas partout. La solution est de faire un "seuillage localement adaptatif" où un seuil différent est calculé pour chaque voisinage de l'image. Il existe de nombreuses façons de le faire, mais vérifiez par exemple:

Un autre problème que vous avez est que les lignes ne sont pas droites. D'après mon expérience, Tesseract peut gérer un degré très limité de lignes non droites (quelques pour cent de distorsion en perspective, d'inclinaison ou d'inclinaison), mais cela ne fonctionne pas ' t vraiment travailler avec lignes ondulées . Si vous le pouvez, assurez-vous que les images source ont des lignes droites :) Malheureusement, il n'y a pas de réponse simple à cela; vous devez vous pencher sur la littérature de recherche et implémenter vous-même l'un des algorithmes les plus modernes (et l'open source si possible - il y a un réel besoin d'une solution open source à cela). Une recherche Google Scholar pour " extraction OCR de lignes courbes " vous permettra de démarrer, par exemple:

Enfin: je pense que vous feriez beaucoup mieux de travailler avec l'écosystème python (ndimage, skimage) qu'avec OpenCV en C++. OpenCV python wrappers sont ok pour des choses simples, mais pour ce que vous essayez de faire, ils ne feront pas le travail, vous devrez saisir de nombreuses pièces qui ne sont pas dans OpenCV (bien sûr, vous pouvez mélanger et assortir). Implémenter quelque chose comme la détection de ligne courbe dans C++ prendra un ordre de grandeur plus long qu'en python (* c'est vrai même si vous ne connaissez pas python).

Bonne chance!

45
Alex I
  1. La numérisation à 300 dpi (points par pouce) n'est pas officiellement une norme pour l'OCR (reconnaissance optique de caractères), mais elle est considérée comme l'étalon-or.

  2. La conversion de l'image en niveaux de gris améliore la précision de lecture du texte en général.

J'ai écrit un module qui lit le texte dans Image qui à son tour traite l'image pour un résultat optimal de l'OCR, Image Text Reader .

import tempfile

import cv2
import numpy as np
from PIL import Image

IMAGE_SIZE = 1800
BINARY_THREHOLD = 180

def process_image_for_ocr(file_path):
    # TODO : Implement using opencv
    temp_filename = set_image_dpi(file_path)
    im_new = remove_noise_and_smooth(temp_filename)
    return im_new

def set_image_dpi(file_path):
    im = Image.open(file_path)
    length_x, width_y = im.size
    factor = max(1, int(IMAGE_SIZE / length_x))
    size = factor * length_x, factor * width_y
    # size = (1800, 1800)
    im_resized = im.resize(size, Image.ANTIALIAS)
    temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.jpg')
    temp_filename = temp_file.name
    im_resized.save(temp_filename, dpi=(300, 300))
    return temp_filename

def image_smoothening(img):
    ret1, th1 = cv2.threshold(img, BINARY_THREHOLD, 255, cv2.THRESH_BINARY)
    ret2, th2 = cv2.threshold(th1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    blur = cv2.GaussianBlur(th2, (1, 1), 0)
    ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    return th3

def remove_noise_and_smooth(file_name):
    img = cv2.imread(file_name, 0)
    filtered = cv2.adaptiveThreshold(img.astype(np.uint8), 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 41,
                                     3)
    kernel = np.ones((1, 1), np.uint8)
    opening = cv2.morphologyEx(filtered, cv2.MORPH_OPEN, kernel)
    closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel)
    img = image_smoothening(img)
    or_image = cv2.bitwise_or(img, closing)
    return or_image
14
Amit Kushwaha

Remarque: cela devrait être un commentaire pour Alex, je réponds, mais c'est trop long, donc je le mets comme réponse.

extrait de "An Overview of the Tesseract OCR engine, by Ray Smith, Google Inc." sur https://github.com/tesseract-ocr/docs/blob/master/tesseracticdar2007.pdf

"Le traitement suit un pipeline traditionnel étape par étape, mais certaines étapes étaient inhabituelles à l'époque, et le restent peut-être même maintenant. La première étape est une analyse des composants connectés dans laquelle les contours des composants sont stockés. décision de conception coûteuse en calcul à l'époque, mais qui présentait un avantage important: en inspectant l'imbrication des contours et le nombre de contours des enfants et petits-enfants, il est simple de détecter le texte inverse et de le reconnaître aussi facilement que le texte en noir sur blanc . Tesseract a probablement été le premier moteur OCR capable de gérer de manière aussi triviale du texte blanc sur noir. "

Il semble donc qu'il ne soit pas nécessaire d'avoir du texte noir sur fond blanc, et devrait également fonctionner à l'opposé.

5
AndrewBloom