Clean scanned book pages — remove bleed-through, ghosting, and uneven shadows
debleed takes a poorly scanned PDF (or a folder of photos) and produces clean,
white, readable pages. It removes reverse-side text bleeding through
(bleed-through), uneven lighting, ghosting artifacts, and any other
illumination mess.
- soft — smooth grayscale with anti-aliasing, ideal for screen reading
- binary — Sauvola binarization, maximum contrast, 1-bit output (tiny files)
- adaptive — OpenCV adaptive threshold (original method, fallback)
git clone https://github.com/umi008/debleed.git
cd debleed
uv syncGPU acceleration (CUDA):
uv sync --extra gpuOr with pip:
python3 -m venv .venv
source .venv/bin/activate
pip install .# test on 5 pages to dial in parameters
debleed scanned_book.pdf output/ --sample 5 --mode binary
# process full book to binary + PDF
debleed scanned_book.pdf output/ --mode binary --pdf
# soft grayscale (easier on the eyes for tablets/readers)
debleed scanned_book.pdf output/ --mode soft --pdf --gamma 1.4
# from a folder of images
debleed original_pages/ clean_pages/ --mode binary --jobs 4
# assemble existing clean PNGs into a PDF (no reprocessing)
debleed scanned_book.pdf output/ --pdf-only| argument | default | description |
|---|---|---|
--mode |
binary |
soft (grayscale), binary (Sauvola), adaptive (OpenCV) |
--k |
0.25 |
Sauvola sensitivity. raise (0.30-0.40) if bleed-through persists |
--window |
auto (dpi/4) | Sauvola window size. larger = smoother |
--bg-ksize |
auto (dpi/5) | Background kernel. larger = removes coarser shadows |
--min-size |
auto (~dpi) | Remove speckles smaller than this (px) |
--dpi |
300 |
Rasterisation DPI (PDF input) |
--sample |
0 |
Process only N pages (for quick tuning) |
--deskew |
off | Straighten tilted pages |
--denoise |
off | Median blur 3x3 pre-filter |
--jobs |
CPUs | Parallel workers |
--no-gpu |
off | Force CPU even with CUDA |
--sauvola-scale |
4 |
Downscale factor for Sauvola (4 = 16x faster) |
| symptom | fix |
|---|---|
| bleed-through visible | raise --k to 0.30-0.40, or lower --white to 190 (soft) |
| text breaks / thins out | lower --k to 0.18-0.22, or raise --bg-ksize |
| speckles / noise | raise --min-size or use --denoise |
| too contrasty, losing detail | switch to --mode soft and tweak --gamma |
| slow on large books | lower --dpi to 200, or raise --sauvola-scale |
PDF or images → rasterise (if PDF) → grayscale
↓
estimate background
(morphological closing + blur)
↓
normalise (divide by background)
→ removes shadows, attenuates bleed-through
↓
soft / sauvola / adaptive
↓
despeckle (remove speckles)
↓
clean PNGs → [optional] PDF
- grayscale — convert to 8-bit grayscale
- background — estimate the paper illumination field using elliptical morphological closing + Gaussian blur. This isolates shadows regardless of text density
- divide — divide the original by the background. Reverse-side text becomes faint because it is less opaque than front-side text
- binarize — Sauvola with downscaling (faster than OpenCV adaptive threshold for bleed-through), or smooth level adjustment
- despeckle — remove connected components smaller than
--min-size
If you have an NVIDIA GPU with CUDA, debleed accelerates step 2
(illumination normalisation) via CuPy automatically. Use --no-gpu to
force CPU. For huge books on CPU, --no-gpu --jobs $(nproc) gives the
best throughput.
MIT