Detect Words · PixText
You Know a Word in That Caption Is Wrong. Detect Words Finds All of Them.
- image_in
- image
- detections
- words_preview
Every text-to-image model eventually hands you a sign, a label, or a caption with one word melted into soup. You can see it's wrong. What you can't do, without a lot of squinting and dragging, is tell PixText where the wrong word is - the whole thing runs on rectangles and target strings, and you have to supply both by hand.
Detect Words · PixText exists to hand you those rectangles. It reads the image, finds every word in it, and OCRs each one, so the rest of the workflow becomes "which of these do I tick and retype" instead of "draw 13 boxes in the right places."
What it actually runs
Two models, both local, both installed once, no API and no key:
- CRAFT does the detection - the word-box detector EasyOCR uses, run at 1280px with a 1.5 magnification factor.
- PP-OCRv6 medium does the recognition - an ONNX model that reads each cropped quad.
The detector emits quads, the quad gets perspective-warped flat, gets fed to the recognizer at 48px height in BGR order (the official PP-OCR preprocessing, not RGB), and the output is greedily CTC-decoded against the model's own character dictionary. Words come back sorted top-to-bottom then left-to-right, so the numbering in the preview reads like a human scan.
Everything runs on CPU - deliberately. It costs you zero VRAM, and it's the one part of this pack you can run while a 12B model sits in your graphics card. It's also not fast on a dense poster, though results do cache: the node fingerprints the model files plus the image.
The inputs you'll touch
The required image is a dropdown of files in ComfyUI/input plus a bundled example: English caption. Upload through it like any Load Image node. There's also an optional image_in socket for when the picture comes from upstream in the graph.
text_threshold (default 0.5) is how sure CRAFT has to be that a pixel blob is text. link_threshold (default 0.2) is how eagerly it joins blobs into one word. Both are marked advanced for a reason: leave them alone until something breaks. If a word's box looks like it's swallowing the space around it, text_threshold up a notch; if a long word is splitting into three boxes, nudge link_threshold.
The outputs
Three, and you need all of them eventually:
detections- the JSON document the Region Editor consumes: word boxes, recognized text, per-word confidence, and adetection_id. Every region arrives withenabled: false, which matters. The node is telling you these are suggestions, not edits.image- the pixels it actually analyzed, EXIF-corrected to upright RGB. Wire this into the Region Editor'simage_in. The editor checks that the image and the detections share a source hash, so feeding it mismatched halves is caught rather than silently misaligned.words_preview- your image with numbered, color-coded boxes drawn on it, also pushed to the canvas as a preview. This is the node's real payoff: one glance and you know whether detection found the word you care about.
Install
cd ComfyUI/custom_nodes/PixText
python -m pip install -r requirements-ocr.txt
python scripts/download_ocr_models.py --output ../../models/pixtext_ocr
That's the OCR half only, on top of the pack itself. The two installs are genuinely separate: requirements.txt for the refiner is a single entry (opencv-python-headless, since ComfyUI already supplies torch, torchvision, Pillow and numpy), while requirements-ocr.txt pulls easyocr==1.7.2, onnxruntime and PyYAML. The script pulls three files with pinned SHA-256 checks - craft_mlt_25k.pth and the two PP-OCRv6 ONNX/YAML files - into ComfyUI/models/pixtext_ocr.
Restart ComfyUI afterwards. There is no lazy download at inference time; the code refuses to proceed rather than phoning home mid-workflow.
Where people get burned
The error you'll actually see is a list:
Install the optional OCR models in models/pixtext_ocr first. Missing: craft_mlt_25k.pth, ...
That means the download script either wasn't run or was pointed at the wrong output directory. Note the path: models/pixtext_ocr, with an underscore, is a different folder from models/pixtext where the refiner's model packages live. Two folders, easy to merge in your head, and the node won't find either if you mix them.
The second: a busy image can exceed 256 detected words, at which point the node raises rather than quietly truncating, and suggests cropping the image or raising text_threshold. Honest behavior, but if you're doing a page of small print, crop to the block you care about first - refinement caps at 12 targets per pass anyway, so detecting 200 words you won't edit buys nothing.
And remember what the boxes are: guesses. OCR on a damaged word reads the damage, so the text often comes back as the misspelling itself - a starting point you'll overwrite in the editor. The node's job ends once you have rectangles with roughly right text in them.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image | COMBO | example: English caption | 2 options: example: English caption, example.png |
| text_threshold | FLOAT | 0.500.1–0.95 | — |
| link_threshold | FLOAT | 0.200.1–0.95 | — |
| image_inopt | IMAGE | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| detections | PIXTEXT_DETECTIONS | — |
| words_preview | IMAGE | — |