DepthEdgeFilter
Kill the 'flying pixels' before they ruin your point cloud
- depth
- mask
- valid_mask
If you've ever turned a depth map into a point cloud and seen a halo of stray dots hovering around the silhouette of every object, you've met "flying pixels." They're the points at depth discontinuities - the boundary between a foreground object and the background behind it - where the depth value is garbage, partway between the two. DepthEdgeFilter finds those boundary pixels and hands you a mask you can use to throw them away before they pollute the 3D.
It's the first filter I'd recommend adding to any depth-to-point-cloud graph, right after the estimator. The pack's own README calls it out in the video-to-4D pipeline as an optional cleanup for exactly this reason, and it costs almost nothing to run.
How it works
The heuristic is dead simple and effective: a pixel is an edge when the depth gradient relative to the depth itself is too big. The relative_threshold (default 0.05) is the sensitivity knob - a pixel gets flagged as an edge where |depth gradient| / depth exceeds it. Raise it toward 0.1+ if you're losing too much real geometry, lower it toward 0.02 if stray points are still getting through.
dilate (default 1) grows the detected edges by that many pixels using max-pool, which is usually a good idea: the true garbage zone is wider than a single pixel, and dilating one or two pixels catches the penumbra of bad estimates. There's also an optional mask input - a validity mask that gets ANDed with the result. That's handy for combining this with other filters (like a sky mask) so the output is a single validity mask you can pass downstream.
The output is valid_mask (MASK), and the polarity is worth memorizing: 1.0 where depth is valid, 0.0 on the edges. So you don't take the mask and keep it - you take it and use it to cut. In DepthToPointCloud you'd wire it into the mask input to drop those points; in a splat pipeline you'd mask the depth before lifting.
Where it slots in
- After
DepthEstimatorNodeand beforeDepthToPointCloud- the classic position, keeps flying pixels out of the cloud entirely. - In
VideoToFusedSplats-style pipelines the README suggests it as a companion to depth-based motion masking, since the same edge pixels also flicker between frames in video. - It accepts depth shaped
[H,W],[T,H,W], or with a trailing channel dim, so it works on single frames and frame sequences alike.
Install
Shared camera-comfyUI install: Manager → search "camera-comfyUI" → Install, or clone https://github.com/Alexankharin/camera-comfyUI into custom_nodes/ and run python install.py. It's pure torch math on the depth tensor - no model downloads, no CUDA requirement, runs on CPU fine.
Troubleshooting
- Your point cloud is now full of holes at object borders: threshold too aggressive or
dilatetoo high. Backrelative_thresholdup toward 0.08–0.1 and drop dilate to 1. - Stray points still in the cloud: threshold too loose. Step it down 0.03–0.04 and re-check; also make sure the depth itself is ray depth, not Z-depth, or the whole geometry is bowed and the "edges" you're filtering are meaningless.
- Mask looks inverted from what your next node expects: remember, 1 = valid here. If the downstream node wants 1 = edge, hit it with an invert before wiring it in.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| depth | TENSOR | — | |
| relative_threshold | FLOAT | 0.0500–10 | Mark a pixel as edge where |depth gradient| / depth exceeds this value. |
| dilate | INT | 10–64 | Grow detected edges by this many pixels (max-pool dilation). |
| maskopt | MASK | Optional validity mask ANDed with the edge-filter result. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| valid_mask | MASK | — |