🚀 OCR in Python mit PyTesseract#

🔔 Feinlernziel(e) dieses Kapitels
Sie können die notwendigen Schritte zur Verarbeitung eines einseitigen und eines mehrseitigen PDFs zu einem Text aufzählen und das Ursprungs- sowie das Zielformat nennen und Unterschiede erklären.

Kurze Einführung in Jupyter-Notebooks#

Was Sie im Moment sehen, ist ein Jupyter-Notebook. Jupyter ermöglicht es Ihnen, Python-Code in Ihrem Browser zu schreiben und auszuführen. Notebook-Zellen mit Code sehen so aus:

print('Hallo Welt!')
Hallo Welt!

Um die Code-Zellen auszuführen, müssen Sie das Notebook entweder lokal (mit lokaler Jupyter-Instanz) oder in der Cloud mit Binder oder Colab ausführen. Dadurch werden Code-Zellen ausführbar. Um Code in der Zelle auszuführen, treten Sie darauf und drücken Sie Cmd/Strg + Enter oder verwenden Sie die ‘Play button’ links neben der Zelle.

Eine weitere nützliche Tastenkombination ist Umschalt+Enter. Sie führt die Shell aus und geht zur nächsten über. Nützlich, wenn Sie durch viele Zellen klicken müssen.

Hinweise zur Ausführung des Notebooks#

Dieses Notebook kann auf unterschiedlichen Levels erarbeitet werden (siehe Abschnitt “Technische Voraussetzungen”):

  1. Book-Only Mode

  2. Cloud Mode: Dafür auf 🚀 klicken und z.B. in Colab ausführen.

  3. Local Mode: Dafür auf Herunterladen ↓ klicken und “.ipynb” wählen.

Kommentare 📝 vs. Code in Jupyter-Notebooks ⚙️#

  • Die Teile der Codezellen, die mit # beginnen, sind Kommentare für Menschen, um den Code zu erklären

  • Lokale Jupyter-Umgebung hebt Kommentare in grün-blau hervor

  • Colab hebt Kommentare in grün hervor

  • JupyterBook hebt Kommentare in dunkelgelb hervor

  • Kommentare sind keine Python-Befehle und werden nicht ausgeführt

# I am a comment, I do nothing, I'm just here for you to read
print('I am a print function, part of Python code, I print whatever is in these brackets!')
I am a print function, part of Python code, I print whatever is in these brackets!

OCR mit Python#

In diesem Notizbuch werden wir pyTesseract ausführen, um maschinenlesbaren Text zu erzeugen aus:

  • einem JPEG-Bild

  • einem mehrseitigen PDF

  • einem Korpus mehrseitiger PDFs

Informationen zum Ausführen des Notebooks – Zum Ausklappen klicken ⬇️

Voraussetzungen zur Ausführung des Jupyter Notebooks

  1. Installieren der Bibliotheken
  2. 2. Laden der Daten (z.B. über den Command `wget` (s.u.))
  3. 3. Pfad zu den Daten setzen
Zum Testen: Ausführen der Zelle "load libraries" und der Sektion "Einlesen des Texts".
Alle Zellen, die mit 🚀 gekennzeichnet sind, werden nur bei der Ausführung des Noteboos in Colab / JupyterHub bzw. lokal ausgeführt.

Installationen und Importe #

Hide code cell content
#  🚀 Install libraries  
!sudo apt install tesseract-ocr
!sudo apt install tesseract-ocr-frk
!sudo apt install poppler-utils
!pip install pytesseract pillow
!pip install pdf2image
!pip install tqdm
Hide code cell content
import pytesseract
from PIL import Image
from pathlib import Path
from pdf2image import convert_from_path
from tqdm import tqdm

Verarbeitung eines Bildes #

Hide code cell content
!wget https://raw.githubusercontent.com/dh-network/quadriga/refs/heads/main/data-input/grippe.jpeg
../_images/grippe.jpeg

So können wir OCR auf dieses Bild des Zeitungsartikels (‘Die Grippe wütet weiter’) durchführen:

ocr_output = pytesseract.image_to_string(Image.open('grippe.jpeg'), lang='frk') 
print(ocr_output)
Zie Grippe wüfel weiter

Zunahme der ſchweren Fälle in Berlin.

Die Zahl der Grippefälle iſt in den lezten
beider Tagen auch in Groß-Berlin noH
erf>lig zeftiegen. Die Warenhäuſer und ſon-
Haen aroßen GeſHöäfte, die Krirgs- unh die prie
n Betriebe lagen, daß übermäig viele An«-

. fich 5cben rep? melden müſſen,-und an<
; .“ Loft und 5ei der Straßenbahn iſt der
ſos der Grippelranten bedeuten) gt&

MeB 4 2 8 1

Verarbeitung eines (mehrseitigen) PDFs#

Mit ein wenig mehr Python-Code können wir pytesseract auch verwenden, um gesamte PDF-Dateien mit vielen Seiten zu OCRen:

Informationen zum Ausführen des Notebooks – Zum Ausklappen klicken ⬇️ Zuerst wird der Ordner angelegt, in dem die Textdateien gespeichert werden. Der Einfachheit halber wird die gleich Datenablagestruktur wie in dem GitHub Repository, in dem die Daten gespeichert sind, vorausgesetzt.
Der Text wird aus GitHub heruntergeladen und in dem Ordner ../data/pdf/ abgespeichert.
Der Pfad kann in der Variable sample_pdf_path angepasst werden. Die einzulesenden Daten müssen die Endung `.pdf` haben.
Was ist ein Dateipfad? (klicken)

Ein Dateipfad ist eine Zeichenkette, die deinem Programm sagt, wo eine Datei auf deinem Computer oder Server gespeichert ist. Er hilft dem Programm, Dateien zu finden und auf sie zuzugreifen, um sie zu lesen, zu schreiben oder zu bearbeiten.

Arten von Dateipfaden:#

  1. Absoluter Dateipfad:
    Ein absoluter Pfad gibt den vollständigen Speicherort einer Datei ausgehend vom Stammverzeichnis deines Systems an.

    • Beispiel unter Windows:
      C:\Users\JohnDoe\Documents\file.txt

    • Beispiel unter macOS/Linux:
      /Users/JohnDoe/Documents/file.txt

  2. Relativer Dateipfad:
    Ein relativer Pfad zeigt dem Programm, wie es eine Datei basierend auf dem aktuellen Arbeitsverzeichnis (dem Ordner, in dem dein Skript ausgeführt wird) finden kann.

    • Beispiel:
      Documents/file.txt
      (Dies sucht die Datei in einem Ordner namens Documents innerhalb des aktuellen Verzeichnisses).

Pfadtrennzeichen:#

  • Unter Windows verwenden Pfade Backslashes (\):
    C:\folder\file.txt

  • Unter macOS/Linux verwenden Pfade Schrägstriche (/):
    /folder/file.txt

Beispiel in Python:#

# Absoluter Pfad
file = open('C:/Users/JohnDoe/Documents/file.txt')
    
# Relativer Pfad
file = open('Documents/file.txt')

Python bietet auch Tools, um Pfade so zu handhaben, dass sie auf jedem Betriebssystem funktionieren, wie die Module os und pathlib. Wir verwenden oben pathlib, damit dieses Notebook auf jedem Rechner funktioniert. Dadurch können wir Pfade im Unix-Stil schreiben.

Hide code cell content
# 🚀 Create data directory path
corpus_dir = Path("../data/pdf")
if not corpus_dir.exists():
    corpus_dir.mkdir(parents=True)
Hide code cell content
# 🚀 Load the txt file from GitHub 
! wget https://raw.githubusercontent.com/dh-network/quadriga/refs/heads/main/data/pdf/SNP27112366-19181224-0-0-0-0.pdf

# move the file to the data directory
! mv SNP27112366-19181224-0-0-0-0.pdf ../data/pdf
# set the path to file to be processed
sample_pdf_path = Path("../data/pdf/SNP27112366-19181224-0-0-0-0.pdf")

Dieser Code liest eine mehrseitige PDF-Datei mit einer Zeitungsausgabe vollständig ein und führt Seite für Seite eine Texterkennung (OCR) durch. Die Ausführung wird mehrere Minuten dauern

# this code here reads an entire PDF with a newspaper issue 
# and performs OCR page by page
# it will take a couple of minutes to run
recognized_pages = []
converted_pdf = tqdm(convert_from_path(sample_pdf_path, use_cropbox=True))
for image in converted_pdf:
    recognized = pytesseract.image_to_string(image, 
                                             lang='frk') 
    #print(recognized)
    recognized_pages.append(recognized)

Schauen wir uns die erste Seite an:

print(recognized_pages[0])

Letzte Seite:

print(recognized_pages[-1])

Keines dieser Ergebnisse sieht besonders gut aus (hauptsächlich aufgrund der Scan-Qualität und allgemeiner Herausforderungen bei der Arbeit mit alten Zeitungen). In den nächsten Abschnitten werden wir lernen, wie man

  • a) die OCR-Qualität misst

  • b) die Qualität in der OCR-Nachkorrekturphase verbessert

Um die OCR-Funktion auf einer anderen PDF-Datei auszuführen, müssen Sie in der obigen Zeile einen Dateipfad dazu angeben: sample_pdf_path = Path('/path/to/your.pdf').

(Advanced) Verarbeitung des gesamten Korpus von PDFs mit derselben OCR-Engine #

Der untenstehende Code verarbeitet alle Dateien im Ordner '../data/pdf', die die Endung ‘.pdf’ haben, und speichert die Ergebnisse dann im Ordner '../data/txt' (die Dateinamen bleiben gleich, aber mit der Endung ‘.txt’ anstelle von ‘.pdf’). WARNUNG: Bei einer großen Anzahl (>5) von PDFs wird dies viel Zeit in Anspruch nehmen.

Hide code cell content
# 🚀 Create txt directory path
corpus_dir = Path("../data/txt")
if not corpus_dir.exists():
    corpus_dir.mkdir(parents=True)
pathpdf = Path('../data/pdf')
pathtxt = Path('../data/txt')
for filename in tqdm(pathpdf.iterdir()):
    if filename.suffix == '.pdf':
        converted_pdf = convert_from_path(filename, use_cropbox=True)
        output_path = pathtxt / filename.stem 
        output_path = output_path.with_suffix('.txt')
        with output_path.open('w') as output_txt:
            for image in converted_pdf:
                recognized = pytesseract.image_to_string(image, 
                                                         lang='frk') 
                output_txt.write(recognized)