Tutorial sobre detecção de texto de documento denso

Público-alvo

O objetivo deste tutorial é ajudar você a desenvolver aplicativos usando a detecção de texto de documentos da API Cloud Vision do Google Cloud. 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 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 Cloud Vision que faz uma DOCUMENT_TEXT_DETECTION solicitação e processa a fullTextAnnotation resposta.

fullTextAnnotation é uma resposta hierárquica estruturada com 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 uma matriz de símbolos.

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

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

Listagem de código completa

Ao ler o código, recomendamos que você acompanhe a referência da API 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)

Este aplicativo executa as seguintes tarefas:

  • 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 do arquivo em que o Cloud Vision vai gerar uma imagem 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

As seções a seguir examinam os principais componentes do aplicativo de amostra em detalhes.

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 Cloud 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, analisamos os argumentos transmitidos e os passamos para a função render_doc_text().

Como autenticar na API

Antes de se comunicar com o serviço da API Cloud Vision, você precisa autenticar seu serviço usando as credenciais já adquiridas. A maneira mais simples de receber credenciais em um aplicativo é usar Application Default Credentials (ADC). Por padrão, as bibliotecas de cliente do Cloud tentam receber as credenciais da variável de ambienteGOOGLE_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 Cloud 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 Cloud 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 em a solicitação. 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 do recurso do documento especificado.

Como executar o aplicativo

Para executar o aplicativo, você pode fazer o download deste arquivo receipt.jpg (talvez seja necessário clicar com o botão direito no link) e, em seguida, transmitir 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 Cloud Vision.