5.2. 🚀 Regelbasierte OCR-Nachbearbeitung#

5.2.1. 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.

5.2.2. Übersicht#

In diesem Notebook wird eine regelbasierte OCR-Nachkorrektur entwickelt und angewendet. Ziel ist es, typische Fehler, die beim OCR-Prozess historischer Texte entstehen, automatisch zu beheben und die Verbesserung messbar zu machen.

Dafür werden folgende Schritte durchgeführt:

  1. Identifikation typischer OCR-Fehler im Korpus (z.B. < statt ch, fie statt sie, ſ statt s)

  2. Implementierung von Korrekturregeln mit regulären Ausdrücken

  3. Anwendung der Regeln auf ein Beispielbild mittels Tesseract-OCR

  4. Messung der Verbesserung anhand von Precision, Recall und F1-Score im Vergleich mit einem Ground-Truth-Text

  5. (Advanced) Anwendung der Korrekturregeln auf das gesamte Korpus

Hide code cell content
# 🚀 Install libraries
import sys
if 'google.colab' in sys.modules:
    !sudo apt install tesseract-ocr
    !sudo apt install tesseract-ocr-frk
!pip install pytesseract pillow Levenshtein
Requirement already satisfied: pytesseract in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (0.3.10)
Requirement already satisfied: pillow in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (10.3.0)
Requirement already satisfied: Levenshtein in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (0.25.0)
Requirement already satisfied: packaging>=21.3 in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (from pytesseract) (24.0)
Requirement already satisfied: rapidfuzz<4.0.0,>=3.1.0 in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (from Levenshtein) (3.7.0)
Hide code cell content
import re
import pytesseract
from PIL import Image
from pathlib import Path
from tqdm import tqdm

5.2.3. Typische Fehler#

Im Folgenden listen wir einige typische Fehler in unserem Korpus auf:

  • „fie“ statt „sie“ (Bild und Ergebnis später hinzufügen)

  • „vm“, „vnd“ statt „um“, „und“

  • „<“ statt „ch“

Einige Dinge sind keine Fehler, sondern Merkmale der historischen Orthographie, die wir für die weitere Verarbeitung mit modernen NLP-Tools normalisieren möchten:

  • „ſ“ statt „s“

In vielen Fällen können wir dies mit einigen regulären Such- und Ersetzungsmustern beheben (z.B. jedes <, das nicht von Leerzeichen umgeben ist, in ch umwandeln).

Der Standardweg, solche Muster auf einem Computer auszudrücken und zu implementieren, sind reguläre Ausdrücke. Mehr über reguläre Ausdrücke erfahren Sie hier.

5.2.4. Implementierung von Regeln für typische Fehler mit regulären Ausdrücken#

def post_correct_text(ocr_output):
    cleaner_output = re.sub(r'(\w)<(\w)', '\\1ch\\2', ocr_output)
    cleaner_output = re.sub(r'(\w)5(\w)', '\\1s\\2', cleaner_output)
    cleaner_output = re.sub(r'\bv(m|nd)\b', 'u\\1', cleaner_output)
    cleaner_output = re.sub(r'\bfie\b', 'sie', cleaner_output)
    cleaner_output = cleaner_output.replace('ſ','s')
    #cleaner_output = cleaner_output.replace('\n',' ')
    return cleaner_output

5.2.5. Anwendung der Regeln auf die OCR-Ergebnisse #

Hide code cell content
!wget https://raw.githubusercontent.com/quadriga-dk/Text-Fallstudie-1/refs/heads/main/assets/images/grippe.jpeg
../_images/grippe1.jpeg
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
ocr_output_corr = post_correct_text(ocr_output)

Lass uns sehen, wie sich das Ganze verändert hat:

print(ocr_output_corr)
Zie Grippe wüfel weiter

Zunahme der schweren Fälle in Berlin.

Die Zahl der Grippefälle ist in den lezten
beider Tagen auch in Groß-Berlin noH
erf>lig zeftiegen. Die Warenhäuser und son-
Haen aroßen GesHöäfte, die Krirgs- unh die prie
n Betriebe lagen, daß übermäig viele An«-

. fich 5cben rep? melden müssen,-und an<
; .“ Loft und 5ei der Straßenbahn ist der
sos der Grippelranten bedeuten) gt&

MeB 4 2 8 1

5.2.6. Messung der Verbesserung#

Hide code cell content
# only for colab users, to download the auxiliary file with the function to measure the quality of the OCR output
import sys

if 'google.colab' in sys.modules:
    import os
    os.makedirs('auxiliary', exist_ok=True)
    !wget -q -O auxiliary/measure_ocr_quality.py https://raw.githubusercontent.com/quadriga-dk/Text-Fallstudie-1/main/ocr_post_correction/auxiliary/measure_ocr_quality.py
Hide code cell content
# 🚀 create folder and get the auxiliary python script to run in Colab
aux_dir = Path("auxiliary")
if not aux_dir.exists():
    aux_dir.mkdir(parents=True)
Hide code cell content
from auxiliary.measure_ocr_quality import measure_ocr_quality

Lass uns sehen, wie sich die regelbasierte Nachkorrektur auf die OCR-Qualitätsmetriken ausgewirkt hat

ground_truth = """Die Grippe wütet weiter 
Zunahme der schweren Fälle in Berlin. 
Die Zahl der Grippefälle ist in den letzten 
beiden Tagen auch in Groß-Berlin noch 
erheblich gestiegen. Die Warenhäuser und son-
stigen großen Geschäfte, die Kriegs- und die pri-
vaten Betriebe klagen, daß übermäßig viele An-
gestellte sich haben krank melden müssen und auch 
bei der Post und bei der Straßenbahn ist der 
Prozentsatz der Grippekranken bedeutend ge-
stiegen."""

Originales (unkorrigiertes) OCR-Ergebnis#

precision, recall, f_score = measure_ocr_quality(ocr_output, ground_truth)
print(f'Precision: {round(precision, 4)}\nRecall: {round(recall, 4)}\nF1-score: {round(f_score, 4)}')
Precision: 0.7864
Recall: 0.8418
F1-score: 0.8132

Korrigiertes OCR-Ergebnis#

precision, recall, f_score = measure_ocr_quality(ocr_output_corr, ground_truth)
print(f'Precision: {round(precision, 4)}\nRecall: {round(recall, 4)}\nF1-score: {round(f_score, 4)}')
Precision: 0.8045
Recall: 0.8613
F1-score: 0.832

Also, unsere F-Score hat sich etwas verbessert, gut!

5.2.7. (Advanced) Ausführung des regelbasierten OCR-Nachkorrekturverfahrens auf dem gesamten Korpus#

pathtxt = Path('../data/txt')
if not pathtxt.exists():
    pathtxt.mkdir(parents=True)
for file in tqdm(pathtxt.iterdir()):
    if file.suffix == '.txt':
        text = file.read_text()
        corrected = post_correct_text(text)
        file.write_text(corrected)