PST
The phase-based edge detector that sees what Canny walks past
- image
- PST
- Kernel
PST - Phase-Stretch Transform - is the original of the PhyCV family, a 2015 algorithm from the UCLA optics lab that everyone else in this pack is built around. You reach for it when your edge map needs to catch edges that are barely there: faint textures, low-contrast transitions, detail buried in noise. Canny works by finding where pixel brightness changes fast. PST instead embeds the image's structure into the phase of its spectrum, stretches that phase with a frequency-dependent "dispersion" (the physics-inspired bit - think light bending through a prism), and reads the edges back out. A faint edge may barely move the gradient, but it still shifts phase. That's the whole advantage, and it's a real one.
How it works
The image gets transformed, its phase spectrum is warped by a nonlinear kernel, and the result is filtered and thresholded back into an edge map. No model, no weights, no API - this is classical signal processing wearing a physics degree, running on the phycv library. The knobs map directly to that pipeline, and the defaults are sane enough to start with.
The inputs that matter
image- any ComfyUI IMAGE, one frame at a time.phase_strength(S, default 0.3) - how aggressively the phase is stretched. More equals more sensitive, and more noisy. This is your main sensitivity dial.warp_strength(W, default 15) - shapes the warp kernel and controls which range of edge lengths the transform responds to. Think of it as your "what size of edge do I care about" knob.sigma_low_pass_filter(default 0.15) - smoothing before thresholding. Crank it up to kill speckle.thresh_min/thresh_max(defaults 0.3 / 0.9) - the gate. Here's the counterintuitive bit: PST keeps edges belowthresh_minand abovethresh_max, and suppresses the middle. Both very faint and very hard edges survive; the mushy middle doesn't. That's by design - it's how one pass keeps detail at both extremes.morph_flag(default true) - morphological cleanup to fill gaps and drop stray specks.
The outputs
Two IMAGEs. The PST output is the edge map - wire that into a ControlNet or img2img. The Kernel output is a visualization of the phase kernel itself, the filter's fingerprint rendered gray. It's a debug curiosity: fun to preview so you can see what the transform is doing, but you don't wire it anywhere you care about.
Where it fits
Use it exactly where you'd use a Canny preprocessor - ControlNet edge conditioning - but for subjects with soft or noisy edges: fur, hair, smoke, mist, grain-heavy photographs. Where Canny produces a frantic mess, PST tends to produce structure. It's also a solid pre-enhancement step before img2img, since it can push contour information the model would otherwise ignore. Don't expect it to beat Canny on clean architectural linework - that's the wrong tool for this job, and it'll show.
Install
The standard two ways:
# Option 1: ComfyUI Manager → Custom Nodes → search "ComfyUI-PhyCV" → install → restart
# Option 2: manual
cd ComfyUI/custom_nodes
git clone https://github.com/JPrevots/ComfyUI-PhyCV
# restart ComfyUI
Dependencies are torch, torchvision, opencv-python, and phycv - Manager installs them. There are no model files to fetch.
The gotchas
Every node in this pack is CUDA-only: the code hardcodes torch.device("cuda") and instantiates the GPU implementations, with no CPU or MPS fallback. On a CPU-only or Apple machine it errors out the moment you queue it. And it's single-image-only - the node assumes one frame, so feeding it a batched tensor scrambles the output. Also, fair warning: the repo ships with no README and the pack has essentially zero community presence - the Comfy Registry entry at v1.0.1 is the entire documentation. You'll tune it by feel, but the defaults are a genuinely good starting point.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| phase_strength | FLOAT | 0.30 | — |
| warp_strength | INT | 15 | — |
| sigma_low_pass_filter | FLOAT | 0.15 | — |
| thresh_min | FLOAT | 0.30 | — |
| thresh_max | FLOAT | 0.90 | — |
| morph_flag | BOOLEAN | true | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| PST | IMAGE | — |
| Kernel | IMAGE | — |