formula_img2latex/README.md
dschlueter eb72d0b0f2 feat: formula_img2latex 0.1.0 – Formelbilder geprüft durch LaTeX ersetzen
Nachbearbeitung für epub2md- und pdf2md-Ausgaben:
scan → recognize (Vision-LLM lokal/OpenRouter) → verify → review → apply/revert.

- Rendern mit pdflatex (Batch, Fehlerisolierung, unsichere Befehle gesperrt),
  Schrift-Presets cm/times/txfonts/palatino/stix/euler, automatische Wahl je Buch
- Bildvergleich in Originalauflösung mit ¼-Pixel-Ausrichtung, Pixel/Punkt-Konsistenz
- Kontrasttest gegen layouttreue Verwechslungsvarianten, Selbstkorrektur per Hill-Climbing
- Pandoc/MathML-Prüfung vor jeder Annahme
- pdf2md: Formelbild per Template-Matching auf der Seite finden, 600-dpi-Neuausschnitt
- Review-Galerie auf localhost (Token-geschützt), idempotentes apply mit Sicherung, revert
- calibrate: Messung an Formelbildern mit TeX im alt-Text (0/600 Falsch-Annahmen)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 03:00:40 +02:00

9.2 KiB
Raw Blame History

formula_img2latex

Nachbearbeitungs-Werkzeug für die Markdown-Ausgaben von epub2md und pdf2md: Formeln, die nur als Bild vorliegen, werden durch LaTeX ersetzt – aber nur, wenn das gerenderte LaTeX nachweislich so aussieht wie das Original. Zweifelsfälle gehen in eine Review-Galerie, alles andere bleibt Bild.

Schritt-für-Schritt-Anleitung: BEDIENUNGSANLEITUNG.md. Hintergrund und ursprüngliche Planung: Idee/.

Stand 0.1.0 (Prototyp). Der Ablauf ist vollständig (scan → erkennen → prüfen → Review → apply/revert) und getestet. Die Annahmeschwellen sind noch nicht endgültig kalibriert; an echten Büchern landet derzeit der größte Teil im Review (siehe Stand und Grenzen).

Ablauf

scan        Bildverweise in chapters/*.md (bzw. pdf2md-Markdown) finden, Formel/Abbildung vorklassifizieren
recognize   LaTeX-Kandidaten von einem Vision-Modell holen: lokal (llama.cpp) zuerst, Cloud (OpenRouter) nur für Ungelöste
verify      Kandidat rendern (pdflatex), mit dem Original vergleichen, Verwechslungsvarianten prüfen, entscheiden
review      Zweifelsfälle im Browser: Original / Render / Overlay / Diff, LaTeX korrigieren und neu prüfen
apply       angenommene Formeln ins Markdown schreiben (aus einer Sicherung, idempotent)
revert      Markdown-Dateien auf den Stand vor apply zurücksetzen
run         scan + recognize lokal + verify + recognize Cloud (nur Ungelöste) + verify
calibrate   Messung an Formelbildern mit bekanntem TeX (Springer-EPUBs: TeX im alt-Text)
python3 formula_img2latex.py run    output/buch       # epub2md-Ausgabeordner
python3 formula_img2latex.py review output/buch
python3 formula_img2latex.py apply  output/buch
python3 epub2md_merge.py output/buch --force          # Gesamtdatei danach neu bauen

Wie geprüft wird

Die OCR liefert nur einen Kandidaten. Entschieden wird über das Bild:

  1. Rendern mit pdflatex (Paket preview, viele Formeln je Lauf, -no-shell-escape, openout_any=p). Unsichere Befehle (\input, \write, \def, \catcode, …) werden vorher abgelehnt. Die Schrift wird je Buch automatisch gewählt: cm, times, txfonts, palatino, stix, euler.
  2. Vergleichen in der Auflösung des Originals: Tinte normalisieren (Transparenz, JPEG-Rauschen, getönter Hintergrund), gleichmäßig skalieren (nie strecken), auf ¼ Pixel ausrichten. Kennzahlen: Korrelation (NCC), SSIM, Abweichungsflecken, Größenabweichung, Pixel pro Punkt. Pixel pro Punkt ist innerhalb eines Buches konstant; Abweichungen verraten falsche Stile (\frac statt \tfrac, \displaystyle).
  3. Kontrasttest gegen Verwechslungsvarianten (confusables.py). Erzeugt werden ~50–160 Varianten, die sich durch je einen typischen Erkennungsfehler unterscheiden: andere Ziffer, hoch statt tief, ,/;, -/+/=, ähnliche Buchstaben, Groß/klein, \mathcal/\mathbb/…, fehlendes Vorzeichen, Strich oder Akzent. Varianten werden layouttreu gerendert (\mathrlap{neu}\mathbin{\phantom{alt}}), damit sich nur das eine Zeichen ändert. Verglichen wird nur dort, wo sich Kandidat und Variante unterscheiden (Likelihood-Test). Der Kandidat muss jede unterscheidbare Variante mit Abstand schlagen.
  4. Selbstkorrektur: Erklärt eine Variante das Bild deutlich besser, wird sie neuer Kandidat (höchstens 3 Schritte). So werden einzelne OCR-Fehler ohne erneute Modellanfrage repariert.
  5. Pandoc-Prüfung: Jede angenommene Formel muss mit pandoc --mathml umsetzbar sein, sonst bliebe sie im späteren EPUB/PDF roher TeX-Text.

Status je Formel: auto_accepted, needs_review, rejected_keep_image, render_failed, no_candidate, not_formula, nach Review accepted_by_human, corrected_by_human, kept_by_human.

Arbeitsordner

<ausgabe>.formulas/          # neben der Ausgabe, weil epub2md --force die Ausgabe ersetzt
├── workspace.json           # Quelle, Schrift, Pixel/Punkt, Schwellen, apply-Zustand
├── formulas/f-<sha12>-<d|i>.json   # je Bild und Darstellung: Kandidaten, Prüfung, Entscheidung
├── review/<id>-{orig,render,diff}.png
└── backup/                  # Markdown-Dateien vor dem ersten apply

Die Datensätze sind über den SHA-256 des Bildes verknüpft. Ein erneuter epub2md-Lauf mit --force verliert deshalb keine Entscheidungen. scan und apply spielen sie ohne neue OCR wieder ein. Modellantworten werden je Modell gespeichert; dasselbe Modell wird nie zweimal nach demselben Bild gefragt.

Quellen

Quelle Erkennung Begrenzer
epub2md-Ordner conversion-report.json (tool: epub2md); Warnungen formula-image markieren sichere Formeln --math auto: $…$/$$…$$, --math tex: \(…\)/\[…\]
pdf2md-Datei <name>.md + <name>_images/ oder --split-Ordner Bildname <pdf>-<seite>-<box>; mit --pdf wird jede Formel per Template-Matching auf der Seite gefunden, mit 600 dpi aus dem Vektor-PDF neu ausgeschnitten und an Mathe-Schriften (CMMI, EURM, …) als Formel erkannt $…$/$$…$$

Abgesetzte Bildformeln gelten als Display-Mathematik, Bilder im Fließtext als Inline-Mathematik. Codeblöcke werden nie verändert. Inline-Formeln, die pdf2md als Glyphensalat im Fließtext ausgibt, sind nicht Teil dieser Version.

Engines

Jede Engine spricht die OpenAI-Chat-API mit Bildteil:

--engine Standard Konfiguration
local llama.cpp-Server http://127.0.0.1:8011/v1, Modell vom Server FORMULA_LOCAL_URL, FORMULA_LOCAL_MODEL, FORMULA_LOCAL_API_KEY
cloud OpenRouter, google/gemini-2.5-flash OPENROUTER_API_KEY, FORMULA_CLOUD_MODEL, FORMULA_CLOUD_URL

Getestet: Qwen3-VL-30B-A3B-Instruct (Q4_K_M + mmproj) auf einer RTX 3090 mit 0,2–0,5 s je Formel; Gehrke Brückenkurs (1329 Bilder) in 9 Minuten.

Stand und Grenzen

Messungen vom 07.10.2026 (Details: calibrate):

  • Synthetisch (Computer Modern, ~1,4 px/pt, JPEG – wie Gehrke): Die korrekte Formel schlägt in 98 % der Fälle alle Verwechslungsvarianten; ein einzelner falscher Startkandidat wird meist repariert.
  • Gehrke Brückenkurs (EPUB, ~1400 Formel-JPGs, CM): Die OCR ist gut. Abgelehnt oder ins Review geschickt wird überwiegend wegen typografischer Abweichungen der OCR, z. B. \xrightarrow{…} statt \stackrel{…}{\longrightarrow}, \vec statt \overrightarrow, Text neben statt über =. Bei einer Pfeillänge verrutscht alles dahinter. Abhilfe in Arbeit: Korrekturrunde, in der das Modell Original und eigenes Render nebeneinander sieht.
  • Springer-Bücher (Liesen, Göllmann): Was im alt-Text kein TeX hat, sind meist komplexe mehrzeilige Formeln eines fremden Satzsystems. Abstände und Klammergrößen weichen ab, der starre Vergleich bestätigt sie nicht → Review.
  • PDF (Hefferon, Euler-Schrift): Einfache Formeln passen mit euler sehr gut (NCC 0,96). Wo Ziffern oder Operatornamen in anderen Schnitten gesetzt sind (serifenloses sgn), wird der Kontrasttest unzuverlässig → Review.
  • Formeln auf farbig hinterlegten Kästen verlieren beim Ersetzen die Hinterlegung.

Nächste Schritte: Schwellen mit calibrate an den layouttreuen Varianten neu festlegen; Korrekturrunde mit Diff-Bild; abschnittsweiser Vergleich (Zeilen/Spalten getrennt ausrichten) für mehrzeilige Formeln fremder Satzsysteme; Inline-Formeln in PDFs.

Installation

sudo apt install texlive-latex-extra texlive-fonts-extra texlive-science pandoc   # pdflatex, Schriften, Pandoc
pip install -r requirements.txt     # pymupdf, numpy, scipy, scikit-image, opencv, Pillow, lxml, requests
pip install -r requirements-dev.txt # pytest

Tests

python3 -m pytest -q     # ca. 30 s; synthetische Bilder, kein Modellserver, keine Buchinhalte

Rückgabecodes: 0 Erfolg, 1 Bedienfehler, 2 Eingabe ist keine epub2md-/pdf2md-Ausgabe, 3 externes Werkzeug fehlt (pdflatex, pandoc, Modellserver), 4 interner Fehler.

Architektur

formula_img2latex/
├── cli.py          Unterbefehle, Exit-Codes
├── pipeline.py     scan, recognize, verify (Prozess-Pool), Entscheidung, apply/revert
├── sources/        epub2md.py, pdf2md.py, base.py (Markdown-Scan, Begrenzer)
├── pdfcrop.py      Formelbild auf der PDF-Seite finden, 600-dpi-Neuausschnitt, Mathe-Schrift-Erkennung
├── classify.py     Formel / unklar / Abbildung (Farbe der Tinte, Graustufen, Größe, Kontext)
├── engines/        Vision-Modelle über die OpenAI-API (llama.cpp, OpenRouter)
├── render.py       pdflatex-Batch, Schrift-Presets, Rasterung
├── imageio.py      Originale laden (PNG/GIF/JPG/SVG, Transparenz, Tönung)
├── compare.py      Ausrichtung, Kennzahlen, Kontrasttest, Diff-Bilder
├── confusables.py  Verwechslungsvarianten, layouttreue Prüfvarianten
├── verify.py       Prüfung + Selbstkorrektur
├── decide.py       Schwellen und Status
├── checks.py       Pandoc/MathML-Prüfung
├── calibrate.py    Messung an Formelbildern mit bekanntem TeX
├── store.py        Arbeitsordner, Datensätze
└── review/         lokaler Review-Server + Seite