StagesTransform

ImageDrawBoxes

Annotate a page with detection boxes or NER entities. Drawing is a pipeline stage, so the annotated page is just another image column.

Import
import { ImageDrawBoxes } from '@stabrise/scaledp'
Group
Transform
Reads
image, boxes
Writes
image
Needs
nothing
Note
Terminal — output is for looking at.
import { Pipeline, ImageDrawBoxes } from '@stabrise/scaledp'

new ImageDrawBoxes({
    inputCols: ['image', 'text', 'ner'],
    outputCol: 'annotated',
    displayDataList: ['entity_group', 'score'],
    lineWidth: 2,
})
Open a two-pass overlay in the builder

The first entry in inputCols is the image; every other entry is a box or entity source. A source with entities is drawn as NER, one with bboxes as boxes — so one stage can annotate a page with both.

displayDataList renders fields above each box, joined by :. Valid names are the schema's own: text, score, angle, x, y, width, height for a box; entity_group, word, score for an entity. Numbers are formatted to two decimals.

whiteList and blackList filter entity groups only.

Colours

color: null (the default) colours by group, and the colour is stable: a given label is the same colour on every render, in the drawn boxes and in visualizeNer's text, because both call colorForGroup. Python picks a random colour per run, which makes two renders of the same document impossible to compare.

import { colorForGroup } from '@stabrise/scaledp'

colorForGroup('person')   // the same HSL string every time

Every entity group the NER models in this library emit has a hue assigned by hand, spaced 18° from its neighbours. Hashing the name alone is not enough: over the default PII labels it gives phone_number and date the same hue and puts person one degree from ip_address, which defeats the point of colouring by group. Any hash over that many labels collides — it is the birthday problem, not a bad multiplier. Names for one concept share a hue on purpose, so phone and phone_number match. A group outside that table still gets a colour, hashed from its name, so a label nobody anticipated still works.

One stage takes one color for all its sources, which is why a two-colour overlay is two chained passes — the second reading what the first wrote. That is how the demo draws detections in cyan and then leaves the entity pass unset, so each kind of PII gets its own colour.

It is a terminal stage

An annotated page is still an image, but feeding it to a detector means detecting through the boxes drawn on top of it. The registry marks the stage terminal for this reason, and column-suggesting interfaces skip it.

Rotated boxes

Drawn as rotated quads, with the label chip riding the box's own top edge. Python places the chip at the envelope corner instead, which detaches it from a steeply rotated box.

Parameters

ParameterTypeDefaultMeaning
inputColsstring[] (2+)['image', 'boxes']The image first, then one or more box, document or entity columns.
colorstringnullOne colour for every box. Unset colours by group instead.
filledbooleanfalseFill boxes as well as outlining them.
lineWidthnumber 0–201Line width
textSizenumber 4–7224Text size
displayDataListstring[][]Rendered above each box, joined by ":". Pick "text" to read the OCR output back off the page.
paddingnumber0Grow each box by this many pixels before drawing.
whiteListstring[][]Draw only these entity groups; empty draws all.
blackListstring[][]Never draw these entity groups.
imageType'png' | 'webp' | 'jpeg''png'Image format

On this page