Tutoriel de détection de document texte dense

Audience

L'objectif de ce tutoriel est de vous aider à développer des applications à l'aide de la détection de documents texte de l'API Google Cloud Vision. Il y est supposé que vous maîtrisez les concepts et les techniques de base de la programmation. Mais même si vous êtes un programmeur débutant, vous devriez pouvoir suivre et exécuter ce tutoriel sans difficulté, puis utiliser la documentation de référence de l'API Cloud Vision pour créer des applications de base.

Prérequis

Annoter une image à l'aide de la reconnaissance optique des caractères d'un document texte

Ce tutoriel vous présente une application de base de l'API Cloud Vision qui envoie une requête DOCUMENT_TEXT_DETECTION, puis traite la réponse fullTextAnnotation.

Un fullTextAnnotation est une réponse hiérarchique structurée pour le texte UTF-8 extrait de l'image. Elle est organisée sous la forme Pages → Blocs → Paragraphes → Mots → Symboles (Page, Block, Paragraph, Word, Symbol) :

  • Page est un ensemble de blocs, plus des méta-informations sur la page : tailles, résolutions (la résolution X et la résolution Y peuvent varier).

  • Block représente un élément "logique" de la page (par exemple, une zone couverte de texte, une image ou un séparateur se trouvant entre des colonnes). Les blocs de texte et de tableau contiennent les principales informations nécessaires à l'extraction du texte.

  • Paragraph est une unité structurelle de texte représentant une séquence ordonnée de mots. Par défaut, les mots sont considérés comme séparés par des sauts de mot.

  • Word est la plus petite unité de texte. Elle est représentée sous la forme d'un tableau de symboles.

  • Symbol représente un caractère ou un signe de ponctuation.

fullTextAnnotation peut également fournir les URL d'images Web correspondant partiellement ou parfaitement à l'image de la requête.

Intégralité du code

Lors de la lecture du code, nous vous recommandons de vous reporter également la documentation de référence de l'API Cloud Vision pour Python.

import argparse
from enum import Enum

from google.cloud import vision
from PIL import Image, ImageDraw

class FeatureType(Enum):
    PAGE = 1
    BLOCK = 2
    PARA = 3
    WORD = 4
    SYMBOL = 5

def draw_boxes(image, bounds, color):
    """Draws a border around the image using the hints in the vector list.

    Args:
        image: the input image object.
        bounds: list of coordinates for the boxes.
        color: the color of the box.

    Returns:
        An image with colored bounds added.
    """
    draw = ImageDraw.Draw(image)

    for bound in bounds:
        draw.polygon(
            [
                bound.vertices[0].x,
                bound.vertices[0].y,
                bound.vertices[1].x,
                bound.vertices[1].y,
                bound.vertices[2].x,
                bound.vertices[2].y,
                bound.vertices[3].x,
                bound.vertices[3].y,
            ],
            None,
            color,
        )
    return image

def get_document_bounds(image_file, feature):
    """Finds the document bounds given an image and feature type.

    Args:
        image_file: path to the image file.
        feature: feature type to detect.

    Returns:
        List of coordinates for the corresponding feature type.
    """
    client = vision.ImageAnnotatorClient()

    bounds = []

    with open(image_file, "rb") as image_file:
        content = image_file.read()

    image = vision.Image(content=content)

    response = client.document_text_detection(image=image)
    document = response.full_text_annotation

    # Collect specified feature bounds by enumerating all document features
    for page in document.pages:
        for block in page.blocks:
            for paragraph in block.paragraphs:
                for word in paragraph.words:
                    for symbol in word.symbols:
                        if feature == FeatureType.SYMBOL:
                            bounds.append(symbol.bounding_box)

                    if feature == FeatureType.WORD:
                        bounds.append(word.bounding_box)

                if feature == FeatureType.PARA:
                    bounds.append(paragraph.bounding_box)

            if feature == FeatureType.BLOCK:
                bounds.append(block.bounding_box)

    # The list `bounds` contains the coordinates of the bounding boxes.
    return bounds

def render_doc_text(filein, fileout):
    """Outlines document features (blocks, paragraphs and words) given an image.

    Args:
        filein: path to the input image.
        fileout: path to the output image.
    """
    image = Image.open(filein)
    bounds = get_document_bounds(filein, FeatureType.BLOCK)
    draw_boxes(image, bounds, "blue")
    bounds = get_document_bounds(filein, FeatureType.PARA)
    draw_boxes(image, bounds, "red")
    bounds = get_document_bounds(filein, FeatureType.WORD)
    draw_boxes(image, bounds, "yellow")

    if fileout != 0:
        image.save(fileout)
    else:
        image.show()

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("detect_file", help="The image for text detection.")
    parser.add_argument("-out_file", help="Optional output file", default=0)
    args = parser.parse_args()

    render_doc_text(args.detect_file, args.out_file)

Cette application simple effectue les tâches suivantes :

  • Elle importe les bibliothèques nécessaires pour exécuter l'application.
  • Elle utilise trois arguments qu'elle transmet à la fonction main() :
    • image_file : le fichier image d'entrée à annoter.
    • output_file : le nom du fichier de sortie dans lequel Cloud Vision générera une image de sortie sur laquelle seront tracés des polygones.
  • Elle crée une instance ImageAnnotatorClient pour interagir avec le service.
  • Elle envoie la requête et retourne une réponse.
  • Elle crée une image de sortie sur laquelle des cadres sont tracés autour du texte.

En détail

Importer des bibliothèques

import argparse
from enum import Enum

from google.cloud import vision
from PIL import Image, ImageDraw

Nous importons des bibliothèques standards :

  • argparse pour permettre à l'application d'accepter les noms de fichiers d'entrée en tant qu'arguments.
  • enum pour l'énumération FeatureType
  • io pour les E/S des fichiers.

Autres importations :

  • La classe ImageAnnotatorClient de la bibliothèque google.cloud.vision pour l'accès à l'API Cloud Vision.
  • Le module types de la bibliothèque google.cloud.vision pour la création des requêtes.
  • Les bibliothèques Image et ImageDraw de la bibliothèque PIL permettent de créer l'image de sortie (image d'entrée sur laquelle ont été tracés des cadres).

Exécuter l'application

parser = argparse.ArgumentParser()
parser.add_argument("detect_file", help="The image for text detection.")
parser.add_argument("-out_file", help="Optional output file", default=0)
args = parser.parse_args()

render_doc_text(args.detect_file, args.out_file)

Ici, nous analysons simplement les arguments transmis, et nous les transmettons à la fonction render_doc_text().

S'authentifier dans l'API

Avant de communiquer avec le service de l'API Vision, vous devez authentifier votre service avec les identifiants précédemment acquis. Dans une application, le moyen le plus simple d'obtenir des identifiants est d'utiliser les identifiants par défaut de l'application. Par défaut, la bibliothèque cliente Cloud tente d'obtenir les identifiants de la variable d'environnement GOOGLE_APPLICATION_CREDENTIALS, laquelle doit être définie de manière à pointer sur le fichier de clé JSON de votre compte de service (consultez la section Configurer un compte de service pour en savoir plus).

Envoyer la requête API et lire les limites du texte à partir de la réponse

Maintenant que notre service d'API Cloud Vision est prêt, nous pouvons accéder au service en appelant la méthode document_text_detection de l'instance ImageAnnotatorClient.

La bibliothèque cliente encapsule les informations sur les requêtes adressées à l'API et sur les réponses obtenues. Voir la documentation de référence de l'API Vision pour obtenir des informations complètes sur la structure d'une requête

def get_document_bounds(image_file, feature):
    """Finds the document bounds given an image and feature type.

    Args:
        image_file: path to the image file.
        feature: feature type to detect.

    Returns:
        List of coordinates for the corresponding feature type.
    """
    client = vision.ImageAnnotatorClient()

    bounds = []

    with open(image_file, "rb") as image_file:
        content = image_file.read()

    image = vision.Image(content=content)

    response = client.document_text_detection(image=image)
    document = response.full_text_annotation

    # Collect specified feature bounds by enumerating all document features
    for page in document.pages:
        for block in page.blocks:
            for paragraph in block.paragraphs:
                for word in paragraph.words:
                    for symbol in word.symbols:
                        if feature == FeatureType.SYMBOL:
                            bounds.append(symbol.bounding_box)

                    if feature == FeatureType.WORD:
                        bounds.append(word.bounding_box)

                if feature == FeatureType.PARA:
                    bounds.append(paragraph.bounding_box)

            if feature == FeatureType.BLOCK:
                bounds.append(block.bounding_box)

    # The list `bounds` contains the coordinates of the bounding boxes.
    return bounds

Une fois la requête traitée par la bibliothèque cliente, la réponse contient un objet AnnotateImageResponse qui consiste en une liste de résultats d'annotation d'image (un par image envoyée dans la requête). Étant donné que nous n'avons envoyé qu'une seule image dans la requête, nous parcourons fullTextAnnotation et nous collectons les limites pour la caractéristique de document spécifiée.

Exécuter l'application

Pour exécuter l'application, vous pouvez télécharger ce fichier receipt.jpg (vous devrez peut-être cliquer avec le bouton droit de la souris sur le lien), puis transmettre l'emplacement du fichier téléchargé sur votre machine locale à l'application de tutoriel (doctext.py).

Voici la commande Python, suivie de l'image de sortie de l'annotation textuelle.

$ python doctext.py receipt.jpg -out_file out.jpg

Sur l'image ci-dessous, les mots sont dans des cadres jaunes et les phrases dans des cadres rouges.

Félicitations ! Vous avez effectué une détection de texte à l'aide de la réponse fullTextAnnotation de Google Cloud Vision.