Tutorial sobre detecção de texto de documento denso

Público-alvo

Nossa meta neste tutorial é ajudá-lo a desenvolver aplicativos usando a detecção de texto do documento da API Google Cloud Vision. Pressupomos que você tenha familiaridade com construtos e técnicas básicas de programação. No entanto, mesmo que seja um programador iniciante, você pode acompanhar e executar o tutorial sem dificuldade, além de usar a documentação de referência da API Cloud Vision para criar aplicativos básicos.

Pré-requisitos

Como anotar uma imagem usando o OCR de texto de documento

Neste tutorial, apresentamos um aplicativo básico da API Vision que faz uma solicitação DOCUMENT_TEXT_DETECTION e processa a resposta fullTextAnnotation.

fullTextAnnotation é uma resposta hierárquica estruturada para o texto UTF-8 extraído da imagem, organizada como Páginas → Blocos → Parágrafos → Palavras → Símbolos:

  • Page é uma coleção de blocos, além de metainformações sobre a página: tamanhos, resoluções. As resoluções X e Y podem ser diferentes.

  • Block representa um elemento "lógico" da página. Por exemplo, uma área coberta por texto, uma imagem ou um separador entre colunas. Os blocos de texto e tabela contêm as principais informações necessárias para extrair o texto.

  • Paragraph é uma unidade estrutural do texto que representa uma sequência ordenada de palavras. Por padrão, as palavras são separadas por quebras.

  • Word é a menor unidade do texto. Ela é representada como um conjunto de símbolos.

  • Symbol representa um caractere ou um sinal de pontuação.

fullTextAnnotation também pode fornecer URLs para imagens da Web que correspondam parcial ou totalmente à imagem na solicitação.

Listagem de código completa

Durante a leitura do código, recomendamos que você consulte a referência da API do 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)

Esse aplicativo simples:

  • Importa as bibliotecas necessárias para executar o aplicativo
  • Transmite três argumentos para a função main():
    • image_file: o arquivo de imagem de entrada a ser anotado
    • output_file: o nome de arquivo de saída em que o Cloud Vision gerará uma imagem de saída com as polyboxes desenhadas
  • Cria uma instância ImageAnnotatorClient para interagir com o serviço.
  • Envia a solicitação e retorna uma resposta.
  • Cria uma imagem de saída com caixas desenhadas em torno do texto.

Mais detalhes sobre o código

Como importar bibliotecas

import argparse
from enum import Enum

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

Importamos bibliotecas padrão:

  • argparse para permitir que o aplicativo aceite nomes de arquivo de entrada como argumentos;
  • enum para a enumeração de FeatureType;
  • io para E/S de arquivos.

Outras importações:

  • A classe ImageAnnotatorClient na biblioteca google.cloud.vision para acessar a API Vision.
  • O módulo types na biblioteca google.cloud.vision para criar solicitações.
  • As bibliotecas Image e ImageDraw da biblioteca PIL são usadas para criar a imagem de saída com caixas desenhadas na imagem de entrada.

Como executar o aplicativo

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)

Neste caso, simplesmente analisamos os argumentos transmitidos e os passamos para a função render_doc_text().

Como autenticar com a API

Antes de se comunicar com a API do Vision, você precisa autenticar seu serviço usando as credenciais já adquiridas. A maneira mais simples de receber credenciais em um aplicativo é usar o Application Default Credentials (ADC). Por padrão, a biblioteca de cliente do Cloud tentará receber as credenciais da variável de ambiente GOOGLE_APPLICATION_CREDENTIALS. Ela precisa ser configurada para indicar o arquivo de chave JSON da conta de serviço. Para mais informações, consulte Como configurar uma conta de serviço.

Como fazer a solicitação de API e ler limites de texto na resposta

Agora que nosso serviço da API Vision está pronto, podemos acessá-lo chamando o método document_text_detection da instância ImageAnnotatorClient.

A biblioteca de cliente inclui os detalhes das solicitações e respostas para a API. Consulte a Referência da API do Vision para saber informações sobre a estrutura de uma solicitação.

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

Depois que a solicitação tiver sido processada pela biblioteca de cliente, a resposta conterá um AnnotateImageResponse para cada imagem enviada. Ele consiste em uma lista de resultados das "Anotações de imagem". Como enviamos apenas uma imagem na solicitação, verificamos todo o TextAnnotation e coletamos os limites para o recurso do documento especificado.

Como executar o aplicativo

Para executar o aplicativo, faça o download deste arquivo receipt.jpg (talvez seja necessário clicar com o botão direito no link) e transmita o local onde você fez o download do arquivo em sua máquina local para o aplicativo do tutorial (doctext.py).

Este é o comando do Python, seguido das imagens de saída da anotação de texto.

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

A imagem a seguir mostra palavras em caixas amarelas e frases em vermelhas.

Parabéns! Você fez a detecção de texto usando as anotações de texto completo do Google Cloud Vision.