StagesRecognise

TesseractRecognizer

Reads exactly the regions a detector found, straightening each one first. This is the stage that connects a detector to recognition.

Import
import { TesseractRecognizer } from '@stabrise/scaledp/ocr'
Group
Recognise
Reads
image, boxes
Writes
document
Needs
tesseract-wasm

PaddleTextRecognizer detects and recognises in a single pass, so boxes from a separate detector never reach it. This stage does the opposite: it reads exactly the boxes it is handed, cropping and straightening each one. PaddleRecognizer is the same idea with PP-OCR doing the reading.

import { Pipeline } from '@stabrise/scaledp'
import { PdfToImage } from '@stabrise/scaledp/pdf'
import { DbnetOnnxDetector, TesseractRecognizer } from '@stabrise/scaledp/ocr'

const rows = await new Pipeline([
    new PdfToImage(),
    new DbnetOnnxDetector({ outputCol: 'boxes' }),
    new TesseractRecognizer({ inputCols: ['image', 'boxes'] }),
]).transform(file)
Open in builder

Document.type is 'tesseract-recognizer'. A missing box column produces a helpful OcrError in exception rather than an empty result.

boxLevel decides how fine the output boxes are

'word' is the default: Tesseract's own word boxes, mapped back through the crop — padding, scaleFactor and the rotation included — so a word inside a skewed line comes back skewed the same way. Python has no equivalent; the words were always in the response, only their geometry was being discarded.

'region' restores ScaleDP's behaviour: one box per region the detector found, carrying everything read inside it. Since the detectors here are line-level, so are those boxes.

PaddleRecognizer takes the same parameter with the same default, so swapping the engine does not change how finely the page comes back.

scoreThreshold gates the region in both modes, so switching boxLevel changes how finely the result is cut up and nothing else.

Gating each word separately would also change what was read: a word scoring 0.3 between two at 0.9 rides out on the region's mean and would vanish on its own, so the same page would yield different text depending on the box size asked for. Each word still carries its own confidence in score, to filter on downstream.

onlyRotated defaults the other way from Python

ScaleDP defaults it to true, because there the stage refines an OCR pass that already ran and skipping upright boxes is the whole point. Standalone it is the primary recognizer, and that default would return an empty document for the ordinary detector-then-recognize pipeline.

Set it to true to use the stage as a fix-up pass over boxes that already carry text.

Straightening

The crop is a perspective warp onto the box's own axes, verified readable end to end at 0, +25 and −18 degrees. Recognition quality on skewed text is then bounded by the detector: a box whose reported angle does not match the text's produces a crop that is still skewed.

padding defaults to 5, which is what ScaleDP hardcodes. scaleFactor resizes the page before cropping — useful for small text — and coordinates are divided back out, so the boxes stay in the page's own space.

detectLineOrientation classifies each crop 0°/180° and turns the inverted ones before reading, using the same ~9 MB model as LineOrientationDetector.

A Python bug not reproduced

ScaleDP sets b.conf but filters on b.score, so its scoreThreshold is applied to the detector's score rather than the recognizer's. Here it gates the recognition confidence, as the name says.

Parameters

ParameterTypeDefaultMeaning
inputColsstring[] (2)['image', 'boxes']The page image, then the detector output whose regions to read.
langstring[]['eng']Tesseract language codes, e.g. eng or eng, deu. Each needs its traineddata file.
boxLevel'word' | 'region''word'Word boxes are Tesseract’s own. Pick “region” to get one box per region the detector found instead, which is what Python ScaleDP returns.
scaleFactornumber 0.1–81Resize the page by this factor before cropping.
paddingnumber5Grow each box before cropping. ScaleDP hardcodes 5.
endPaddingnumber 0–20.3Extend each region along its line by this fraction of its height, stopping at the next region -- recovers a handwritten capital or flourish the detector left off. 0 reads regions as detected.
dropNestedbooleantrueSkip a region lying mostly inside a larger one, such as a loose stroke of a handwritten capital, since the larger region already reads it.
scoreThresholdnumber 0–10.5Drop words below this confidence.
keepFormattingbooleanfalseRebuild the original layout with spaces and blank lines.
lineTolerancenumber0Line-grouping tolerance in pixels; 0 derives it from character height.
detectLineOrientationbooleantrueClassify each crop 0°/180° and turn the inverted ones.
onlyRotatedbooleanfalseRead only rotated or inverted boxes. On, an ordinary page returns nothing.

On this page