Instructivo de detección de texto en documentos densos

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. Suponemos que estás familiarizado con las construcciones y las 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 previos

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 necesaria 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

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)

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

from google.cloud import vision
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 google.cloud.vision para acceder a la API de Vision.
  • El módulo types dentro de la biblioteca 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().

Autenticar en la API

Antes de comunicarte con el servicio de la API de Vision, debes autenticar tu servicio con las 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 apuntar 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 de 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.

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

Una vez que la biblioteca cliente controla la solicitud, nuestra respuesta contendrá una AnnotateImageResponse que consiste de 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 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!