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. 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 explica el funcionamiento de una aplicación básica de la API de Vision que realiza una solicitud DOCUMENT_TEXT_DETECTION y, luego, procesa la respuesta fullTextAnnotation.

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

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

  • Block representa un elemento “lógico” de la página, por ejemplo, un área cubierta por texto o una foto 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 del 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 más pequeña del texto. Se representa como un arreglo de símbolos.

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

fullTextAnnotation también puede proporcionar URL a imágenes web que coinciden de forma parcial o total con la imagen de 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)

        if (feature == FeatureType.PAGE):
            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.PAGE)
    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 is not 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: el archivo de imagen de entrada que se anotará.
    • output_file: el nombre de archivo de salida en el que Cloud Vision generará una imagen de salida con polyboxes dibujados.
  • 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 las 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 a la aplicación aceptar los nombres de archivo de entrada como argumentos
  • enum para la enumeración FeatureType
  • io para la E/S de archivos

Otras importaciones son:

  • La clase ImageAnnotatorClient de la biblioteca google.cloud.vision para acceder a la API de Vision
  • El módulo types de la biblioteca google.cloud.vision para construir solicitudes
  • Las bibliotecas Image e ImageDraw de la biblioteca 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 lo 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 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, podremos acceder al servicio mediante la 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.

"""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)

    if (feature == FeatureType.PAGE):
        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 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 (puede 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!

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...

Documentación de la API de Cloud Vision
Si necesitas ayuda, visita nuestra página de asistencia.