Anleitung zur Erkennung von Dokumenttext

Zielgruppe

Diese Anleitung soll Ihnen die Anwendungsentwicklung mithilfe der Dokumenttexterkennung der Google Cloud Vision API erleichtern. Es wird davon ausgegangen, dass Sie mit grundlegenden Programmierkonstrukten und -techniken vertraut sind. Aber auch als Einsteiger in die Programmierarbeit sollten Sie dieser Anleitung gut folgen und im Anschluss unter Verwendung der Referenzdokumentation für die Cloud Vision API einfache Anwendungen erstellen können.

Vorbereitung

Bild mit Dokumenttext-OCR annotieren

In dieser Anleitung wird anhand einer einfachen Vision API-Anwendung die Verwendung der Anfrage DOCUMENT_TEXT_DETECTION sowie die Verarbeitung der Antwort fullTextAnnotation erläutert.

Eine fullTextAnnotation ist eine strukturierte hierarchische Antwort zum UTF-8-Text, der aus dem Bild extrahiert wurde. Die Auflistung erfolgt nach Seiten→Blöcken→Absätzen→Wörtern→Symbolen:

  • Page ist eine Sammlung von Blöcken mit Metainformationen zur Seite: Größen und Auflösungen. Die X- und die Y-Auflösung können abweichen.

  • Block steht für ein "logisches" Element der Seite, beispielsweise einen Textbereich, ein Bild oder eine Spaltentrennung. Die Text- und Tabellenblöcke enthalten die wichtigsten Informationen für die Textextrahierung.

  • Paragraph ist eine strukturelle Texteinheit, die eine geordnete Wortfolge darstellt. Standardmäßig wird davon ausgegangen, dass zwischen Wörtern Worttrennungen vorhanden sind.

  • Word ist die kleinste Texteinheit. Sie wird als eine Reihe von Symbolen dargestellt.

  • Symbol steht für ein Zeichen oder Satzzeichen.

Mit der fullTextAnnotation können auch URLs zu Webbildern angegeben werden, die teilweise oder vollständig mit dem Bild in der Anfrage übereinstimmen.

Vollständige Codeliste

Wir empfehlen, beim Lesen des Codes die Python-Referenz für die Cloud Vision API hinzuzuziehen.

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)

Diese einfache Anwendung führt folgende Aufgaben aus:

  • Importiert die für die Ausführung der Anwendung erforderlichen Bibliotheken
  • Übergibt drei Argumente an die Funktion main():
    • image_file: die eingegebene Bilddatei, die annotiert werden soll
    • output_file: der Name der Ausgabedatei, in der mit Cloud Vision ein Ausgabebild mit vieleckigen Rahmen (Polygonen) generiert wird
  • Erstellt die Instanz ImageAnnotatorClient für die Interaktion mit dem Dienst
  • Sendet die Anfrage und gibt eine Antwort zurück
  • Erstellt ein Ausgabebild, in dem der Text eingerahmt ist

Erläuterung des Codes

Bibliotheken importieren

import argparse
from enum import Enum

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

Importieren Sie Standardbibliotheken:

  • argparse, damit die Anwendung eingegebene Dateinamen als Argumente akzeptiert
  • enum für die Aufzählung FeatureType
  • io für Datei-E/A

Weitere Importe:

  • Die Klasse ImageAnnotatorClient in der Bibliothek google.cloud.vision für den Zugriff auf die Vision API
  • Das Modul types in der Bibliothek google.cloud.vision zum Erstellen von Anfragen
  • Die Bibliotheken Image und ImageDraw der Bibliothek PIL werden verwendet, um das Ausgabebild mit auf das Eingabebild gezeichneten Feldern zu erstellen.

Anwendung ausführen

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)

Hier parsen Sie einfach die eingereichten Argumente und übergeben sie an die Funktion render_doc_text().

Bei der API authentifizieren

Damit Sie mit dem Vision API-Dienst kommunizieren können, müssen Sie den Dienst mit den zuvor abgerufenen Anmeldedaten authentifizieren. Innerhalb einer Anwendung erhalten Sie die Anmeldedaten am einfachsten über die Verwendung der Standardanmeldedaten für Anwendungen (Application Default Credentials, ADC). Die Clientbibliothek versucht standardmäßig, die Anmeldedaten von der Umgebungsvariable GOOGLE_APPLICATION_CREDENTIALS abzurufen. Diese muss auf die JSON-Schlüsseldatei Ihres Dienstkontos verweisen. Weitere Informationen finden Sie unter Dienstkonto einrichten.

API-Anfrage stellen und Markierungsrahmen aus der Antwort lesen

Der Vision API-Dienst ist nun bereit. Rufen Sie die Methode document_text_detection der Instanz ImageAnnotatorClient auf, um auf den Dienst zuzugreifen.

Die Details zu API-Anfragen und -Antworten sind in der Clientbibliothek enthalten. Ausführliche Informationen zum Aufbau einer Anfrage finden Sie in der Vision API-Referenz.

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

Nachdem die Clientbibliothek die Anfrage verarbeitet hat, wird als Antwort eine AnnotateImageResponse mit einer Liste mit je einer Anmerkung zu jedem in der Anfrage gesendeten Bild zurückgegeben. Da unsere Anfrage nur ein Bild enthielt, gehen wir die vollständige TextAnnotation durch und erfassen die Markierungsrahmen für das angegebene Dokumentelement.

Anwendung ausführen

Zum Ausführen der Anwendung können Sie die Datei receipt.jpg herunterladen. Klicken Sie gegebenenfalls mit der rechten Maustaste auf den Link. Übergeben Sie anschließend auf Ihrem lokalen Computer den Speicherort der heruntergeladenen Datei an die Anleitungsanwendung (doctext.py).

Hier sehen Sie den Python-Befehl gefolgt von den Ausgabebildern mit Textanmerkungen.

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

Im folgenden Bild sind Wörter gelb markiert und Sätze rot umrahmt.

Glückwunsch! Sie haben mithilfe von Google Cloud Vision eine Texterkennung mit vollständigen Textanmerkungen durchgeführt.