Generate mask from text
Mask the text out of an image automatically — OCR plus thresholding
- image
- MASK
Generate mask from text finds the text in an image and hands you back a mask covering it. No manual painting, no SAM click-to-select - you feed it an image, it OCRs it with EasyOCR, combines that with a contrast threshold, and out comes a MASK you can feed straight into an inpaint. If you've ever needed to strip watermarks, logos, subtitles, or baked-in text from a batch of images without hand-masking each one, this is the node that does it automatically.
How it works
It's a two-pass intersection, and understanding it tells you where it'll fail. First it runs an adaptive threshold on the grayscale image to find "high-contrast pixel blobs" - the raw shape mask. Then it runs EasyOCR to find text regions, draws those bounding boxes into a second mask, and keeps only the pixels where both masks agree (a bitwise AND). Finally it optionally dilates the result so you're masking a little beyond the exact glyphs - usually what you want before inpainting, so the editor has context to work with instead of razor-thin letterforms.
The clever part is the combination: thresholding alone masks every high-contrast region (including your subject's edges), and OCR alone gives you sloppy boxes. The AND of the two is "high-contrast pixels that are inside a detected text region" - which is a much better text mask than either alone.
The inputs that matter
- language_name - 44 languages from English to 简体中文 to Arabic. Pick the one your text is in; EasyOCR is per-language and defaults to English. A mismatch is the most common reason you get an empty mask.
- ocr_confidence_threshold (0.0–1.0, default 0.3) - drop it if text is being ignored; raise it if false positives are creeping in.
- use_gpu (default true) - EasyOCR runs much faster on CUDA. If your PyTorch lacks GPU support it silently falls back to CPU.
- threshold_block_size (default 11) and threshold_c (default 7) - the adaptive-threshold knobs. If the shape mask is grabbing too much or too little, these are what you tune.
- dilation_iterations (default 0) and dilation_kernel_size (default 3) - grow the mask outward after combining. Start at 1–2 iterations for watermark removal; the inpainter will thank you.
Output: a single MASK, wired into any inpaint node (LaMa, Flux Fill, or a masked SD inpainting pass).
Installation
Part of the comfyui_LLM_Polymath pack, but with a heavy catch: it needs easyocr, and EasyOCR pulls in torch and downloads its own detection/recognition model files on first use. Install the pack via ComfyUI Manager (search "comfyui_LLM_Polymath") or clone into custom_nodes and pip install -r requirements.txt. If easyocr is missing at startup, the pack prints a warning and this node simply doesn't register - so if the node isn't in your list, that's the first thing to check. First run also triggers the model downloads, which can take a minute; a "no text detected" result on a first try is sometimes just the models still warming up. Batches larger than one are handled by processing only the first image, so don't feed it a stack expecting per-frame masks.
Where it bites
The honest limit, straight from the community: people who've automated watermark removal report that EasyOCR is great on clean printed text and misses stylized logos and semi-transparent watermarks. On a plain "remove this subtitle" job it's excellent; on a glossy logo over a busy product photo, expect misses - raise the confidence threshold down and bump dilation, or accept that some images need a manual touch-up pass.
And keep your expectations calibrated by the era you're in: instruction-editing models (Qwen-Image-Edit, Flux Kontext) can often just be told "remove the text, change nothing else" with no mask at all. The mask approach still wins when you need the rest of the image pixel-identical - you composite the inpainted region back and nothing else moved. For batch-cleaning datasets where every pixel outside the text matters, that's exactly the trade you want.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| language_name | COMBO | English | 44 options: English, 简体中文, 繁體中文, العربية, Azərbaycan, Euskal, +38 |
| ocr_confidence_threshold | FLOAT | 0.300–1 | — |
| use_gpu | BOOLEAN | true | — |
| threshold_block_size | INT | 113–51 | — |
| threshold_c | INT | 71–20 | — |
| dilation_iterations | INT | 00–10 | — |
| dilation_kernel_size | INT | 31–11 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| MASK | MASK | — |