An optional Tesseract 5 second pass, for the scripts OneOCR cannot read.
Website · All repositories · Live output
OneOCR reads Latin, Devanagari and Tamil well. On the other Indic scripts it fails silently —
it returns text in a different script, or Latin gibberish, with no error raised and a page-level
confidence that still looks healthy. On a real bilingual court order it rendered
દેખીએ આપકે લીએ દો તીન question હૈ as Devanagari हेजीये खापडे सीखे हो तीन question है.
This module supplies the engine for a second pass that re-reads only the lines a confidence guard
flags. The orchestration lives in oneocr-cli; this module knows nothing about
OneOCR's output format.
Measured on a 300 DPI page: a tesseract.exe invocation costs 276 ms of process startup and
model loading against 339 ms for a real line — so 81% of every per-line call is overhead.
Re-reading twelve lines that way costs about as much as OCRing the whole page, which defeats the
point of touching only the flagged minority.
With the DLL the models stay resident: 108 ms per line, ~120 ms per model during a probe. Two further things an external binary cannot do at all:
- the result iterator yields word boxes and per-word confidences, needed to match OneOCR's output shape
- several models stay initialised at once, which is what makes per-line language probing affordable
There is deliberately no default candidate set. Which scripts a document might contain is a
property of the caller's corpus, not of this library, so the candidate list always comes from the
caller. TessLangs offers presets (indic, installed) as a convenience, never as an assumption.
Identification is by competition rather than script detection — Tesseract's own OSD is useless here,
reporting Latin even for an isolated Gujarati line. Instead each candidate model reads the line and
the winner is taken on mean confidence, accepted only if it scores at least 85 and beats the base
language by at least 10. Both tests are needed: the margin rejects lines that are really just
low-confidence English, and the absolute floor rejects scripts the probe cannot identify (those score
51–63 and are declined rather than guessed at).
Nothing is bundled. Traineddata is fetched on first use from tessdata_best and cached under
~/oneocr/tessdata. Pin the upstream revision with
-Doneocr.tessdata.revision=<sha-or-tag> for reproducibility. A full nine-language Indic set is
about 105 MB, which is exactly why it is not shipped.
- JDK 22+ (FFM is final;
--enable-native-accessis required at runtime) - Tesseract 5.4+ installed. Found via
TESSERACT_HOME,%LOCALAPPDATA%\Programs\Tesseract-OCR,C:\Program Files\Tesseract-OCR, orPATH. Install withwinget install tesseract-ocr.tesseract.
try (var pool = new TessPool(List.of("guj", "hin"), "eng", 300)) {
var vote = pool.probe(lineImage); // which script is this?
if (vote.accepted()) {
var result = pool.recognize(lineImage, vote.lang());
System.out.println(result.text());
}
}TessPool.verify(image, lang) confirms an already-known language for two engine runs instead of the
full sweep — use it before replacing anything, since the guard that selects candidate lines also
catches ordinary low-confidence text in the base language.
TessBaseAPIis not thread safe; use oneTessEngineper thread.- Gurmukhi is not reliably identified by the probe. It fails safe (declines) rather than choosing wrongly, but needs an explicit language hint.
- Thresholds are calibrated on one real document plus synthetic pages. Clean renders flatter them; noisy scans will compress the margins.