π English Word Annotator
Turn any generated scene into a labeled vocabulary card β boxes and English words, no drawing by hand
- image
- bboxes
- labels
- image
The name sounds fancier than the job, and that's the point. π English Word Annotator doesn't detect anything, call any API, or need a key. It's a pure renderer: you hand it an image, a list of bounding boxes, and a list of English labels, and it draws a colored rectangle around each object with the word printed in a little colored tag. It was built for one specific thing - vocabulary learning cards - and it's honestly the cleanest way to get there in ComfyUI.
Here's the workflow it's meant to sit in. Generate a scene (SDXL, Flux, whatever - the README demos Z-Image-Turbo), then run Florence-2 in detection mode to get per-object boxes and labels, then feed both into this node and save the result. The rendering step is the part nobody wants to hand-roll in PIL, and that's the whole package: one node, one file, about 250 lines.
How it works
The mechanism is boring in the best way. The image input (an IMAGE tensor) gets converted to a PIL image, boxes are drawn with ImageDraw, labels are stamped in a filled pill above or inside each box, and the result goes back to an IMAGE tensor. Two details save you from real pain:
- An
AnyTypewildcard onbboxesandlabels. Florence-2 wrappers have changed their output shape across releases - flat lists, batch-wrapped lists, even{"bbox":..., "label":...}dicts from older versions. This node normalizes all of them. If you're fighting a type mismatch between Florence-2 versions, this is the node that shrugs and works. - Sensible fallbacks. Boxes are clipped to image bounds, degenerate boxes are skipped, and if a label tag doesn't fit above the box it falls back inside. If you're missing a label for a box, you get
#1,#2β¦ instead of a crash.
An 8-color palette cycles so adjacent boxes stay distinguishable - no two neighbors get the same tint.
The inputs that matter
Required: image, bboxes, labels. That's it - everything else has a sensible default.
label_position(above/inside_top/below) - where the word tag sits.aboveis the default and usually the right call for study cards;inside_topif objects run to the top edge.font_size(default 36) andbox_width(default 4) - text size and outline thickness. Bumpfont_sizefor big classroom cards.max_labels(default 0, and 0 = no limit) - cap how many objects get annotated. Handy when Florence-2 finds 20 regions and you only want the first five.font_pathandtext_color(both optional) - an explicit TTF path if you hate the defaults, and a hex text color.
One output: image. Wire it straight into SaveImage or PreviewImage. It only draws on the first frame of a batch, so don't feed it a video.
Install
It's two minutes. Either ComfyUI Manager (search "English Annotator") or:
cd ComfyUI/custom_nodes
git clone https://github.com/aadebuger/ComfyUI-EnglishAnnotator.git
cd ComfyUI-EnglishAnnotator
uv pip install -r requirements.txt # just Pillow + numpy
Restart ComfyUI and it appears under π English Annotator. The node itself is featherweight - the real dependency is upstream: you'll also want kijai/ComfyUI-Florence2 (and its Florence-2-base/large weights, which download on first run and can be several GB). The README's example flow is CheckpointLoader β KSampler β VAEDecode feeding the image, with Florence2ModelLoader β Florence2Run feeding boxes and labels.
Gotchas
- Labels render as empty boxes or squares on a fresh headless Linux box - no fonts installed.
sudo apt install fonts-dejavu-corefixes it. - Florence-2 is the fragile half. Its
transformersdependency needs>=4.41but can clash with other packs locked to 4.x; ifFlorence2ModelLoadercomplains, upgrade it but stay below 5.0. Andflash_attnimport errors - setattention="sdpa"onFlorence2Run. - Long labels overflow their colored pill - the box is clamped to the image edge but the text isn't wrapped, so a word like "refrigerator" on a small box will spill right. Keep words short or bump
font_sizedown. - Uses
uv pip install, notpipif your venv is uv-managed - uv venvs ship no pip, andpython -m pipwill just fail.
For task mode, od gives clean COCO category names; caption_to_phrase_grounding is the one to reach for when you have a fixed vocabulary list and want Florence-2 to lock onto exactly those words - which is precisely the daily-vocab pipeline this node was built for.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | β | |
| bboxes | * | β | |
| labels | * | β | |
| font_size | INT | 368β256 | β |
| box_width | INT | 41β20 | β |
| label_position | COMBO | above | 3 options: above, inside_top, below |
| font_pathopt | STRING | β | |
| text_coloropt | STRING | #FFFFFF | β |
| max_labelsopt | INT | 00β100 | 0 = no limit |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | β |