Nodes/ComfyUI_PhaseCongruencyEdge/Phase Congruency Edge
ComfyUI Node

Phase Congruency Edge

Phase Congruency Edge

By bemoregt·Created 7 months ago·Updated 7 months ago· 1
Phase Congruency Edge
  • image
  • phase_congruency_edge
nscale4
norient6
min_wavelength3
mult2.1
sigma_on_f0.55
k2.0
cutoff0.50

You've got a batch of images where Canny fires perfectly on half of them and goes blind on the rest, because one was shot in shadow and another blew out its highlights. That's the exact problem this node exists for. Phase Congruency Edge is an edge detector that keys on phase, not brightness, so a gradient or a shadow doesn't move the edge - only the actual edge does.

It's a direct port of Peter Kovesi's 1999 phase congruency algorithm, which has quietly lived in computer vision papers for decades without ever getting a friendly UI. This node is that friendly UI. The trade: it's slower and needs a few knobs understood, but when you need edges that survive lighting changes, Canny doesn't even compete.

What it does under the hood

Classic detectors (Sobel, Canny, Laplacian) look at intensity gradients - which means their output changes when the light does. Phase congruency flips the question. It looks at the image in the frequency domain (via FFT) and asks where the Fourier components of different scales line up in phase with each other. At a real edge, all the wave components hit their peak together. In a flat region or noise, they don't. So the detector finds locations where components are "maximally in phase" - regardless of their amplitude. That's what makes it illumination- and contrast-invariant.

The node builds log-Gabor filters at nscale scales and norient orientations, applies them in the frequency domain, sums the complex responses into an energy vector per orientation, estimates a noise threshold from Rayleigh statistics, and computes max(energy − T, 0) / (sum of amplitudes). The final map is the mean across orientations, normalized to 0–1. White = strong edge. It feeds a grayscale (actually RGB-replicated) phase_congruency_edge IMAGE out.

The inputs that matter

There are eight inputs and you'll touch maybe three. The rest are defaults that work:

  • k - noise threshold in standard deviations. This is your main dial. Default 2.0. Lower it toward 1.0 when edges are getting missed (risk: speckle noise). Raise it to 4–6 when the output looks dirty.
  • min_wavelength - fineness of the finest scale filter, in pixels. Lower (2–3) for fine detail, higher (8–20) for coarse, broad edges. Default 3.
  • norient - orientations to check. Default 6 catches all directions; crank to 8 if diagonal edges look weak.

Leave nscale (4), mult (2.1), sigma_on_f (0.55), and cutoff (0.5) alone until you've got a feel for the first three.

Where it fits

In ComfyUI terms, this is a ControlNet preprocessor that ships outside the usual preprocessor pack - a hand-rolled replacement for Canny or lineart when those frustrate you. Wire any IMAGE into it, take the output into a ControlNet Apply (or straight to a save node), and you have a lighting-robust line map for architecture, documents, OCR prep, or stylized edge rendering. It's CPU-only numpy FFT, so on large images expect it to be much slower than Canny - fine for a single image, painful if you feed it a whole video frame batch.

Installing it

ComfyUI Manager is easiest: search ComfyUI_PhaseCongruencyEdge. Or by hand:

cd ComfyUI/custom_nodes
git clone https://github.com/bemoregt/ComfyUI_PhaseCongruencyEdge

Restart ComfyUI and it appears under image/filters → Phase Congruency Edge. No model downloads, no GPU deps - just numpy, pillow, and torch, which ComfyUI already ships. One gotcha: the README's own clone command points at a stale repo name that doesn't exist anymore; the URL above is the live one. That kind of rot is why you check the code, not just the docs.

If output comes out noisy, raise k first - that's the single most common fix. If edges look too heavy or too faint, that's min_wavelength. This is a niche node from a small repo, so don't expect community threads to save you - the math is the spec, and it's the only edge detector you'll meet that genuinely doesn't care what time of day the photo was taken.

Categoryimage/filters

Inputs (8)

NameTypeDefaultDescription
imageIMAGE
nscaleINT42–8Number of wavelet scales
norientINT62–8Number of filter orientations
min_wavelengthINT32–20Minimum wavelength of log-Gabor filter
multFLOAT2.11.5–4Scaling factor between successive filter scales
sigma_on_fFLOAT0.550.1–1Bandwidth of log-Gabor filter
kFLOAT2.00.5–10Noise threshold (std devs above mean)
cutoffFLOAT0.500.1–0.9Fractional measure of frequency spread below which phase congruency values get penalized

Outputs (1)

NameTypeDescription
phase_congruency_edgeIMAGE