Instructivo de texto en documentos

Público

El objetivo de este instructivo es ayudarte a desarrollar aplicaciones con la detección de texto en documentos de la API de Google Cloud Vision. Se supone que estás familiarizado con las construcciones y técnicas de programación básicas. Sin embargo, aunque seas un programador principiante, podrás seguir y ejecutar este instructivo sin dificultad y, luego, usar la documentación de referencia de la API de Cloud Vision para crear aplicaciones básicas.

Requisitos

Anota una imagen con OCR de texto en documentos

En este instructivo, se muestra una aplicación básica de la API de Vision que realiza una solicitud DOCUMENT_TEXT_DETECTION y, luego, procesa la respuesta fullTextAnnotation.

Un fullTextAnnotation es una respuesta jerárquica estructurada para el texto UTF-8 extraído de la imagen, organizada como Páginas → Bloques → Párrafos → Palabras → Símbolos:

  • Page es una colección de bloques, además de metainformación sobre la página: tamaños, resoluciones (la resolución X y la resolución Y pueden variar).

  • Block representa un elemento “lógico” de la página, por ejemplo, un área cubierta por un texto, una imagen o un separador entre columnas. Los bloques de texto y tabla contienen la información principal que se necesita para extraer el texto.

  • Paragraph es una unidad estructural de texto que representa una secuencia ordenada de palabras. Según la configuración predeterminada, se considera que las palabras están separadas por saltos de línea.

  • Word es la unidad de texto más pequeña. Se representa como un arreglo de símbolos.

  • Symbol representa un carácter o un signo de puntuación.

El fullTextAnnotation también puede proporcionar URL a imágenes web que coinciden de forma parcial o total con la imagen en la solicitud.

Muestra el código completo

A medida que leas el código, te recomendamos que consultes la Referencia de la API  de Cloud Vision para Python.

import argparse
    from enum import Enum
    import io

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

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

    def draw_boxes(image, bounds, color):
        """Draw a border around the image using the hints in the vector list."""
        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):
        """Returns document bounds given an image."""
        client = vision.ImageAnnotatorClient()

        bounds = []

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

        image = types.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):
        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)

Esta aplicación simple ejecuta las siguientes tareas:

  • Importa las bibliotecas necesarias para ejecutar la aplicación.
  • Toma tres argumentos y los pasa a la función main():
    • image_file: Es el archivo de imagen de entrada que se anotará
    • output_file: Es el nombre de archivo de salida en el que Cloud Vision generará una imagen de salida con dibujos de polyboxes.
  • Crea una instancia ImageAnnotatorClient para interactuar con el servicio
  • Envía la solicitud y muestra una respuesta.
  • Crea una imagen de salida con cuadros dibujados alrededor del texto.

Un análisis más detallado del código

Importa bibliotecas

import argparse
    from enum import Enum
    import io

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

Importamos las siguientes bibliotecas estándar:

  • argparse para permitir que la aplicación acepte los nombres de archivos de entrada como argumentos
  • enum para la enumeración FeatureType
  • io para la E/S de archivos

Otras importaciones son:

  • La clase ImageAnnotatorClient dentro de la biblioteca de google.cloud.vision para acceder a la API de Vision.
  • El módulo types dentro de la biblioteca de google.cloud.vision para crear solicitudes.
  • Las bibliotecas Image y ImageDraw de la biblioteca de PIL se usan para crear la imagen de salida con cuadros dibujados en la imagen de entrada.

Ejecuta la aplicación

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)

Aquí, simplemente analizamos los argumentos ingresados y los pasamos a la función render_doc_text().

Autentica la API

Antes de comunicarte con el servicio de la API de Vision, debes autenticar tu servicio con credenciales ya adquiridas. Dentro de una aplicación, la manera más simple de obtener credenciales es usar las Credenciales predeterminadas de la aplicación (ADC). Según la configuración predeterminada, la biblioteca cliente de Cloud intentará obtener credenciales de la variable de entorno GOOGLE_APPLICATION_CREDENTIALS que debería estar configurada para que apunte al archivo de claves JSON de tu cuenta de servicio (consulta Configura una cuenta de servicio a fin de obtener más información).

Realiza una solicitud de API y lee los límites de textos de la respuesta

Ahora que tu servicio de la API de Vision está listo, podemos acceder al servicio mediante una llamada al método document_text_detection de la instancia ImageAnnotatorClient.

La biblioteca cliente abarca los detalles para las solicitudes y respuestas a la API. Consulta la Referencia de la API de Vision para obtener información completa sobre la estructura de una solicitud.

"""Returns document bounds given an image."""
    client = vision.ImageAnnotatorClient()

    bounds = []

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

    image = types.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.

Una vez que la biblioteca cliente controla la solicitud, nuestra respuesta contendrá una AnnotateImageResponse que consiste en una lista de resultados de anotación de imagen, una para cada imagen enviada en la solicitud. Debido a que solo enviamos una imagen en la solicitud, repasaremos la TextAnnotation completa y recopilaremos los límites para la característica del documento especificado.

Ejecuta la aplicación

Para ejecutar la aplicación, puedes descargar este archivo receipt.jpg (es posible que debas hacer clic con el botón derecho en el vínculo) y, luego, pasar la ubicación donde descargaste el archivo en tu máquina local a la aplicación del instructivo (doctext.py).

Aquí está el comando de Python, seguido de las imágenes de salida de la anotación de texto.

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

En la siguiente imagen, se muestran las palabras en los cuadros amarillos y las oraciones en rojo.

Felicitaciones Realizaste la detección de texto con las anotaciones de texto completo de Google Cloud Vision.