AdaptiveCannyDetector_PoP
Canny edges, but pre-filtered through adaptive thresholding
- images
- IMAGE
Canny is the classic ControlNet preprocessor - hard, thin edge maps that lock a generation to your source image's structure. Every major ControlNet lineup ships a Canny variant for exactly that reason. This node is the pack author's own reimplementation of it, built, in his words, because he "didn't know how canny edge detection worked so I decided to make my own node and figure it out." The result is genuinely a bit different from the stock Canny preprocessor you'll find in other packs, not just a reskin of it.
How it works
Standard Canny preprocessors run edge detection on a blurred grayscale image and call it done. This one adds a step in between: grayscale → Gaussian blur → adaptive threshold → Canny. Adaptive thresholding (OpenCV's adaptiveThreshold) binarizes the image using a locally-computed threshold per neighborhood rather than one global cutoff, which is what makes it handle uneven lighting better than a flat threshold would. Canny then runs on top of that binarized image, not on the raw blurred grayscale. That ordering is the whole "adaptive" in the name, and it's why edge output from this node can look meaningfully cleaner - or meaningfully different - from a plain Canny node on images with strong lighting gradients or low local contrast.
One thing worth knowing if you're comparing this against other Canny nodes: the classic Canny low/high threshold pair is fixed internally here, not exposed as a control. The knobs you get are all upstream of that - blur and adaptive-threshold settings - so you're tuning what Canny sees, not Canny's own sensitivity.
The inputs and outputs that matter
images- your source image, whatever you want edges from.gaussian_blur_ksize(default 5) andgaussian_blur_sigma(default 0) - how much the image gets softened before thresholding. Higher ksize means less noisy, less detailed edges.adaptive_thresh_method-GAUSSIAN_CorMEAN_C, how the local threshold per neighborhood gets computed. Gaussian weights nearby pixels more; mean treats them equally.adaptive_thresh_type-BINARYorBINARY_INV, which side of the threshold becomes white vs. black.adaptive_thresh_blocksize(default 11) andadaptive_thresh_C(default 2) - the neighborhood size and a constant subtracted from the computed threshold. These are the two you'll actually fiddle with if edges look too sparse or too noisy.- Output is a single
IMAGE- feed it straight into your ControlNet's image input alongside a Canny ControlNet model, same as any preprocessor output.
How to install it
ComfyUI Manager: search "comfy_PoP", install, restart. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/picturesonpictures/comfy_PoP
No models to download and no heavy dependencies - this runs on OpenCV, which ComfyUI already needs for a dozen other things, so if your install works at all, this node works.
Common issues & troubleshooting
Edges look too sparse or broken up. Lower adaptive_thresh_blocksize or nudge adaptive_thresh_C down - a smaller neighborhood or lower subtracted constant tends to keep more local detail.
Edges look noisy or full of speckle. Push gaussian_blur_ksize up first; a stronger blur before thresholding removes a lot of the fine-grain noise that turns into stray Canny pixels.
You need to match a specific low/high Canny threshold from another workflow. You can't, directly - this node doesn't expose those. If you're porting a workflow that depends on tuned Canny thresholds, use a standard Canny preprocessor instead; this one trades that control for the adaptive pre-pass.
Getting good, structural control on a modern union ControlNet? Recent union models (Shakker's Flux union, Alibaba PAI's Qwen/Z-Image/FLUX.2 unions) recommend running Canny conditioning noticeably below the old default 1.0 strength - 0.65–0.8 is typical. That's ControlNet weight advice and applies regardless of which Canny preprocessor fed it, this one included.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| gaussian_blur_ksize | INT | 51–31 | — |
| gaussian_blur_sigma | FLOAT | 0.00–10 | — |
| adaptive_thresh_method | COMBO | 2 options: GAUSSIAN_C, MEAN_C | |
| adaptive_thresh_type | COMBO | 2 options: BINARY, BINARY_INV | |
| adaptive_thresh_blocksize | INT | 113–51 | — |
| adaptive_thresh_C | INT | 20–10 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |