fix: viser_ply filtrage outliers statistiques — supprime gros pâtés bruités
This commit is contained in:
@@ -1,15 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Minimal standalone viser viewer for a single PLY point cloud.
|
"""Minimal standalone viser viewer for a single PLY point cloud."""
|
||||||
|
|
||||||
Usage:
|
|
||||||
python3 viser_ply.py path/to/cloud.ply --port 8200
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
import argparse, sys, time
|
||||||
import argparse
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
@@ -18,10 +10,9 @@ def main():
|
|||||||
ap.add_argument("ply", help="PLY file to visualize")
|
ap.add_argument("ply", help="PLY file to visualize")
|
||||||
ap.add_argument("--port", type=int, default=8200)
|
ap.add_argument("--port", type=int, default=8200)
|
||||||
ap.add_argument("--point-size", type=float, default=0.01)
|
ap.add_argument("--point-size", type=float, default=0.01)
|
||||||
ap.add_argument("--downsample", type=float, default=0.0,
|
ap.add_argument("--downsample", type=float, default=0.0)
|
||||||
help="Voxel downsample size (0 = no downsample)")
|
ap.add_argument("--max-points", type=int, default=2_000_000)
|
||||||
ap.add_argument("--max-points", type=int, default=2_000_000,
|
ap.add_argument("--no-filter", action="store_true", help="Disable outlier removal")
|
||||||
help="Random subsample to this many points if cloud is larger")
|
|
||||||
args = ap.parse_args()
|
args = ap.parse_args()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -31,15 +22,30 @@ def main():
|
|||||||
sys.exit(f"missing dep: {e}")
|
sys.exit(f"missing dep: {e}")
|
||||||
|
|
||||||
pcd = o3d.io.read_point_cloud(args.ply)
|
pcd = o3d.io.read_point_cloud(args.ply)
|
||||||
|
n_raw = len(pcd.points)
|
||||||
|
print(f"loaded {n_raw:,} pts from {args.ply}", flush=True)
|
||||||
|
|
||||||
if args.downsample > 0:
|
if args.downsample > 0:
|
||||||
pcd = pcd.voxel_down_sample(args.downsample)
|
pcd = pcd.voxel_down_sample(args.downsample)
|
||||||
|
print(f"after voxel downsample: {len(pcd.points):,} pts", flush=True)
|
||||||
|
|
||||||
|
if not args.no_filter and len(pcd.points) > 100:
|
||||||
|
# Remove statistical outliers (blobs / noise from low-confidence frames)
|
||||||
|
pcd, _ = pcd.remove_statistical_outlier(nb_neighbors=20, std_ratio=2.0)
|
||||||
|
print(f"after outlier removal: {len(pcd.points):,} pts", flush=True)
|
||||||
|
# Second pass tighter for dense clouds
|
||||||
|
if len(pcd.points) > 200_000:
|
||||||
|
pcd, _ = pcd.remove_statistical_outlier(nb_neighbors=30, std_ratio=1.5)
|
||||||
|
print(f"after 2nd pass: {len(pcd.points):,} pts", flush=True)
|
||||||
|
|
||||||
pts = np.asarray(pcd.points, dtype=np.float32)
|
pts = np.asarray(pcd.points, dtype=np.float32)
|
||||||
cols = np.asarray(pcd.colors, dtype=np.float32) if pcd.has_colors() else np.ones_like(pts) * 0.7
|
cols = np.asarray(pcd.colors, dtype=np.float32) if pcd.has_colors() else np.ones_like(pts) * 0.7
|
||||||
|
|
||||||
if len(pts) > args.max_points:
|
if len(pts) > args.max_points:
|
||||||
idx = np.random.choice(len(pts), args.max_points, replace=False)
|
idx = np.random.choice(len(pts), args.max_points, replace=False)
|
||||||
pts, cols = pts[idx], cols[idx]
|
pts, cols = pts[idx], cols[idx]
|
||||||
print(f"loaded {len(pts):,} pts from {args.ply}", flush=True)
|
|
||||||
|
|
||||||
|
print(f"displaying {len(pts):,} pts", flush=True)
|
||||||
server = viser.ViserServer(host="0.0.0.0", port=args.port)
|
server = viser.ViserServer(host="0.0.0.0", port=args.port)
|
||||||
server.scene.add_point_cloud(
|
server.scene.add_point_cloud(
|
||||||
"/cloud", points=pts, colors=(cols * 255).astype(np.uint8), point_size=args.point_size
|
"/cloud", points=pts, colors=(cols * 255).astype(np.uint8), point_size=args.point_size
|
||||||
|
|||||||
Reference in New Issue
Block a user