- Python 97.1%
- HTML 2.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Entscheidung (Standard: decide=consensus): - Zwei lokale Vision-Modelle (local: Qwen3-VL, local2: Gemma 4) lesen jedes Formelbild; angenommen wird nur bei inhaltlicher Übereinstimmung (Normalform oder Render-Gleichheit), Pandoc-Prüfung und grobem Bild-Veto - Optional dritte Lesart als Gegenprobe (require_third) bzw. Stichwahl - Fettdruck standardmäßig irrelevant (bold_relevant=0) - Token-Wahrscheinlichkeiten aus Logprobs (p_min, p_mean) statt Selbsteinschätzung; "Nachdenken" lokaler Modelle abgeschaltet (Gemma 4: ~10x schneller) - consensus.py: Normalform auf Baumbasis (Abstände, \left/\right, kursiv/aufrecht, Längenvarianten, Matrix-Umgebungen, TeX-Umlaute, \atop), Render-Vergleich Bildvergleich (Veto und Pixel-Modus decide=pixel): - Elastische Ausrichtung per DTW über Spalten und Zeilen; Dehnen kostet proportional zur Tinte, Varianten nutzen die Verzerrung des Kandidaten - Layouttreue Prüfvarianten, Äquivalenzklassen, rauschnormierter Kontrast Werkzeuge: calibrate --consensus, tools/vergleich.py (50er-Stichprobe mit Bildern), tools/konsens_bericht.py (Übersichtsseite); Ausgaben in vergleich/ (nicht versioniert) Messung Göllmann (2 x 150 Formeln, Fettdruck egal): Qwen = Gemma = GLM angenommen 61 % / 57 %, davon falsch 0; Qwen = Gemma allein: 1 bzw. 2 Fehler. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
| formula_img2latex | ||
| Idee | ||
| tests | ||
| tools | ||
| .gitignore | ||
| BEDIENUNGSANLEITUNG.md | ||
| formula_img2latex.py | ||
| pytest.ini | ||
| README.md | ||
| requirements-dev.txt | ||
| requirements.txt | ||
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:
- 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. - 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
(
\fracstatt\tfrac,\displaystyle). - 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. - 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.
- Pandoc-Prüfung: Jede angenommene Formel muss mit
pandoc --mathmlumsetzbar 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},\vecstatt\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
eulersehr gut (NCC 0,96). Wo Ziffern oder Operatornamen in anderen Schnitten gesetzt sind (serifenlosessgn), 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