DbnetOnnxDetector
The same DBNet ONNX text detector ScaleDP runs server-side, in the browser. Rotated, line-level boxes.
- Import
import { DbnetOnnxDetector } from '@stabrise/scaledp/ocr'- Group
- Detect
- Reads
- image
- Writes
- boxes
- Needs
onnxruntime-web
A direct mirror of ScaleDP's DBNetOnnxDetector — same model, same thresholds —
so a detection result can be compared across the two runtimes, with
squareInput: true for exact parity (see below). About 4.8 MB.
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)Unlike Paddle's, these boxes carry a real rotation, which is what makes the detector worth its download on skewed scans.
The three thresholds
They are easy to confuse, and they act at different points:
binaryThreshold(0.5) is per pixel: above this, a pixel counts as text in the probability map. Raise it to break apart touching lines; lower it to stop thin strokes from being lost.scoreThreshold(0.3) is per candidate: the mean in-box probability a region must reach to be kept at all.unclipRatio(2.5) is a size: DB shrinks regions during training, so every candidate is grown back by this ratio. Too low clips descenders; too high merges neighbours.
mergeBoxes then merges overlapping boxes that share a line; ScaleDP uses an
IoU of 0.02 for this.
A Python bug not reproduced
In ScaleDP, scoreThreshold never reaches DBPostProcess — the effective
threshold is the hardcoded 0.3. Here the parameter is wired through, so setting
it does something.
Self-hosting
model accepts a Hugging Face repo id or a URL. A URL is treated as a
single-file model spec and bypasses modelHost entirely.
Input shape: the picture's own, or ScaleDP's square
The picture is scaled so its longer side fits 1280, never distorted, and padded at the bottom and right with white. How far it is padded is the choice:
squareInput: false(default) pads only to the next multiple of 32, which is all the network's strides need. The scale is the same; the input is just smaller. Up to 4× faster on a small or wide picture (a 1000×300 crop: 450 → 115 ms) and about 1.3× on a page.squareInput: truepads to the full 1280×1280 square, as ScaleDP does, and reproduces its boxes exactly.
The model was trained on padded squares and its output depends on the white
around the text, so with the default some boxes move and some lines split
differently from ScaleDP's. Turn squareInput on when the result must match
Python.
Packing small pictures
A square input costs a full 1280×1280 inference whatever is on it. pack
(opt-in) lays several of a page's pictures onto shared squares, separated by
packGutter pixels of white, with the upscale capped at packMaxScale, so a
page with three small pictures runs once instead of three times. A picture
alone on its input comes out exactly as unpacked; pictures sharing one can read
differently, since the network sees its neighbours.
Preprocessing, for the record
After padding, the image is normalised with ImageNet mean and standard deviation in BGR channel order. That reproduces a quirk of the Python implementation — BGR pixels with RGB statistics — and is required for parity. It is not a bug on this side.
Parameters
| Parameter | Type | Default | Meaning |
|---|---|---|---|
model | 'StabRise/text_detection_dbnet_ml_v0.2' | 'StabRise/text_detection_dbnet_ml_v0.1' | 'StabRise/text_detection_dbnet_ml_v0.2' | Hugging Face repo id, or a URL when self-hosting. |
scoreThreshold | number 0–1 | 0.3 | Mean in-box probability a candidate must reach. |
binaryThreshold | number 0–1 | 0.5 | Probability above which a pixel counts as text. |
unclipRatio | number 0.5–5 | 2.5 | How far to grow each box; DB shrinks text regions during training. |
mergeBoxes | boolean | true | Merge overlapping boxes that share a line. Usually changes nothing here — this model already returns one region per line, so no two boxes overlap. |