Text Preserve Preprocessor (OCR)
Text Preserve Preprocessor (OCR)
- image
- processed_image
- text_mask
Ever img2img'd a product shot and watched the brand name melt into abstract squiggles? That's the problem this node is built for. Text Preserve Preprocessor (OCR) is a preprocessor that OCR-detects the text in your image, keeps those pixels crisp and untouched, and aggressively destroys everything else with blur and noise - so a downstream diffusion pass regenerates the background while your label survives intact.
The name is a lie in the best way: it doesn't call any API, needs no key, and runs entirely on your machine. It's also deliberately the inverse of the "remove logo / watermark" nodes people usually build with OCR (the r/comfyui logo-removal threads are a close cousin; this one flips the mask). Same detection, opposite goal: they erase the text, this one shields it.
How it works
Straightforward OpenCV + EasyOCR pipeline, and the source is short enough to read in a minute. Per image in the batch:
- Blur the whole frame (Gaussian,
blur_radius- the node force-corrects it to an odd number if you feed an even one). - Add Gaussian noise to the blurred frame (
noise_sigma, in 0–255 pixel units - so the default 50 is genuinely heavy). - Run EasyOCR on the original image, keep every detection whose confidence is at least
text_threshold, and paint those bounding polygons into a mask. - Dilate the mask by
mask_dilationso you protect a halo around the text, feather it, then composite: original pixels where text is, blur+noise everywhere else.
Output one is processed_image - that's your img2img bait. Output two is text_mask, the text-region mask, so you can reuse the detection downstream.
The inputs that matter
All five are required, and honestly only two of them need your attention:
image- the IMAGE tensor,[B,H,W,C]in 0–1. RGBA is fine; alpha gets silently dropped.blur_radius(default 31, 1–201) - how aggressively the background is destroyed. 21–41 is the sweet spot per the README; too high and the non-text zones turn to soup.noise_sigma(default 50, 0–200) - background chaos. 30–70 gives a natural "this is not the original" nudge so the model actually redraws instead of copying.mask_dilation(default 10, 0–100) - safety margin around the text. 5–15; if you see text getting smeared, raise this.text_threshold(default 0.3, 0–1) - OCR confidence cut. Lower it (0.3 or below) when you have small or stylized text EasyOCR is unsure about.
Wiring it in
The classic graph: Load Image → Text Preserve → VAE Encode → sampler → VAE Decode. Feed processed_image into img2img (or as the reference for a Flux/img2img-style pass) and prompt the background change. The text_mask output is where the subtlety lives: it's 1 where the text is, which is the wrong polarity for most inpaint workflows - those want the mask of the region to change. Invert it (InvertMask) before feeding an inpaint-conditioning node, or skip that entirely and do the belt-and-braces pattern: generate from the noisy background, then ImageCompositeMasked the original text pixels back over the result. Compositing after generation is the standing best practice in the ComfyUI world for exactly this reason - never trust a VAE pass to leave your unmasked pixels alone.
Installing it
ComfyUI Manager: search ComfyUI-Text-Preserve and install. Or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/yangrui511/ComfyUI-Text-Preserve
cd ComfyUI-Text-Preserve
pip install -r requirements.txt
Then restart ComfyUI. Dependencies are opencv-python, numpy, and easyocr - and EasyOCR is the heavy one: it drags in its own torch stack, and on first run it downloads detection + recognition models (this pack hardcodes Chinese-simplified and English, so it pulls both weight sets). Give the first pass a few minutes; the reader is cached globally afterward, so subsequent runs are fast. It tries GPU first and falls back to CPU.
Where people get burned
The big silent trap: EasyOCR is an optional import in the source. If it fails to load, the node substitutes a dummy reader that detects nothing - no crash, no red text, you just get a fully blurred+noised image and an empty mask. Watch the console for EasyOCR import errors after install.
Also set expectations for the OCR itself. EasyOCR nails plain text but routinely misses stylized logos and semi-transparent watermarks (a recurring complaint in the product-image-cleaning threads) - the fix is a bigger mask_dilation and a lower text_threshold, not a better prompt. And remember it's a preprocessor: it protects, it doesn't regenerate. For text removal you want the inpainting stack, not this node.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| blur_radius | INT | 311–201 | — |
| noise_sigma | FLOAT | 500–200 | — |
| mask_dilation | INT | 100–100 | — |
| text_threshold | FLOAT | 0.300–1 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| processed_image | IMAGE | — |
| text_mask | MASK | — |