Document Scanner
Straighten a crooked photo of a page into a clean scan — no API, no model, no key
- image
- scanned_image
- debug_edges
You know that feeling - you've got a slightly crooked phone photo of a receipt, a page, or a whiteboard, and what you actually want is a flat, rectangular "scan" you can save or feed into the next step of the workflow. DocumentScanner is that, as a ComfyUI node. It takes a photo, finds the page, warps it flat, and cleans it up with one of six enhancement methods. The name is a lie in the best way: it calls no API, downloads no model, and needs no key. It's pure OpenCV math running on your machine, so it works on anything you can load into the graph - including the image your checkpoint just generated, if you want your output to look like a scanned document.
It's the flagship node of harishcmgit/comfyui_ds, a small three-node pack that's basically one document-scanner implementation with two simpler front-ends. This is the full-fat version with every knob.
How it works
The pipeline is the classic OpenCV document-scanner recipe you've seen in a hundred tutorials, and it's all in the node's utils.py:
- Preprocessing (optional): a GrabCut foreground/background segmentation runs first to knock out text that would otherwise confuse edge detection. That's what
skip_preprocessingtoggles. - Grayscale + bilateral blur: edge-preserving smoothing, so noise goes away but the page's edges survive.
- Canny edge detection, using the two thresholds you can set.
- Find the document: it looks for the largest convex quadrilateral whose area is over half the frame. That area requirement is worth remembering - the page needs to fill a good chunk of the photo or it won't be found.
- Perspective transform: warps the quadrilateral to a flat rectangle.
- Enhance with whichever of the six methods you picked.
Every step is wrapped in try/except, and the fallback is "return the original image." Which is great for robustness and terrible for feedback, as covered below.
The inputs that matter
image- the photo. It batches, so a list of frames works fine.enhancement_method-sharpening(default, HSV-boosted),cartooning,clahe,threshold(Otsu + denoise),adaptive_threshold(best for text),flat_field(divides out uneven lighting before CLAHE). For text, reach foradaptive_threshold; for photos and mixed content,claheorsharpening.edge_threshold_low/edge_threshold_high- Canny thresholds (defaults 20/70). If the page boundary isn't being detected, lowering both finds more edges.blur_kernel_size- bilateral filter diameter, odd values 3–15. Leave it unless edges are noisy.skip_preprocessing- set true to skip the GrabCut step. Handy when GrabCut is slow or misfires.return_debug_edges- when true, the second output shows the Canny edge map so you can see what the detector saw.
Outputs: scanned_image (the result) and debug_edges (the edge visualization). Wire scanned_image into a SaveImage, a VAE encode, or upscaling. Note that debug_edges is still an IMAGE output even when you don't request it - it's just an all-black tensor, so don't be startled by the black wire.
Installing it
Easiest is ComfyUI Manager - search for comfyui_ds and hit install. Or, the manual way:
cd ComfyUI/custom_nodes
git clone https://github.com/harishcmgit/comfyui_ds
Then restart ComfyUI. Dependencies are just opencv-python and numpy; torch comes with ComfyUI. There are no model files to fetch. One thing to know: the README says pip install -r requirements.txt, but the shipped repo doesn't actually contain a requirements.txt - if your environment lacks OpenCV, pip install opencv-python is all you need.
Gotchas
The silent-fallback is the trap. If detection fails, the node quietly hands back your original image - no error dialog, no red flag. If your output looks identical to your input, that's what happened. This is exactly what return_debug_edges is for: flip it on, look at the edge map, and adjust the thresholds until the page outline is clearly visible.
Also: it's a brand-new pack - a single commit from early 2026, essentially zero community footprint. Custom nodes run arbitrary Python on your machine, so take thirty seconds to skim the repo before you trust it with your workflow. The code is short and readable, which helps.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| enhancement_method | COMBO | sharpening | 6 options: sharpening, cartooning, clahe, threshold, adaptive_threshold, flat_field |
| edge_threshold_low | INT | 201–100 | — |
| edge_threshold_high | INT | 701–255 | — |
| blur_kernel_size | INT | 53–15 | — |
| skip_preprocessing | BOOLEAN | false | — |
| return_debug_edges | BOOLEAN | false | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| scanned_image | IMAGE | — |
| debug_edges | IMAGE | — |