ProjectAndClean
Cleaning a cloud by projecting it and eroding the mask
- pointcloud
- matrix
- cleaned_pointcloud
PointCloudCleaner removes isolated points by voxel density in cloud space. ProjectAndClean takes the other route: it projects the cloud through a 4×4 matrix into an image, looks at which pixels the cloud actually covers, erodes the coverage mask, and deletes the points that land in the eroded-away pixels. Different mechanism, complementary job.
The effect is that you can throw away points from a specific viewpoint's point of view. If you've got a cloud with stray points hanging in front of a surface (the classic speckle from depth estimates at object edges), projecting from a camera where those strays are visible and eroding the mask strips them cleanly. The cleaning happens in projection space, so it's viewpoint-aware in a way the voxel cleaner isn't - points that look like noise from one angle may be perfectly valid from another, and ProjectAndClean only kills the ones that don't survive the mask test for the matrix you gave it.
The inputs
- pointcloud -
N×7tensor. - matrix - the
MAT_4X4camera transform you're projecting through. This is your viewpoint. - projection - PINHOLE / FISHEYE / EQUIRECTANGULAR, and fov for the view.
- width / height - the projection resolution; higher = finer mask = more selective cleaning.
- mode -
erode(default) shrinks the mask and removes points at its boundary;opendoes an erode-then-dilate, which cleans small islands while keeping the overall coverage shape. - kernel_size - morphological kernel (odd, 1–99, default 3). Bigger kernel = more aggressive removal.
- num_iterations - apply the whole pass repeatedly (default 1, max 10) to peel away more layers.
The output, cleaned_pointcloud, stays in the cloud's original frame - the projection is just the test, not a transformation you keep. Same N×7 format, fewer points.
How it works
Each iteration transforms the cloud by the matrix, z-buffer rasterizes it, builds a coverage mask, then morphological ops on that mask decide which pixels are "kept." Points whose pixels were cleaned away get removed from the cloud, and the loop repeats with the shrunken cloud if num_iterations is higher. Buffers are reused internally to keep peak memory down, which matters because the projection grid is width × height - an 8K test grid is a lot of floats.
Installing it
Part of camera-comfyUI. Manager → Custom Nodes Manager → camera-comfyUI → Install → restart, or:
cd ComfyUI/custom_nodes
git clone https://github.com/Alexankharin/camera-comfyUI.git
cd camera-comfyUI && python install.py
No optional dependencies.
Common issues
- You removed geometry you wanted - the mask erodes real surfaces too, especially thin ones. Prefer
openmode (it restores the original footprint) and small kernels before blaming the cloud. - Nothing seems to change - a cloud that already projects cleanly has nothing for the mask to erode. If your noise is inside the coverage (depth-surface bumps, not boundary strays), the voxel cleaner is the right tool instead.
- Slow with a big cloud and high res - the per-iteration rasterize + morphology is real compute. Lower width/height or iterations.
Pick your viewpoint, sweep the floor.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| pointcloud | TENSOR | — | |
| matrix | MAT_4X4 | — | |
| projection | COMBO | 3 options: PINHOLE, FISHEYE, EQUIRECTANGULAR | |
| fov | FLOAT | 90.00 | — |
| width | INT | 5121–16384 | — |
| height | INT | 5121–16384 | — |
| mode | COMBO | erode | 2 options: erode, open |
| num_iterations | INT | 11–10 | — |
| kernel_size | INT | 31–99 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| cleaned_pointcloud | TENSOR | — |