1. 矿用激光雷达点云去噪与地面分割预处理

井下点云为什么必须先“洗”再“分”

矿用激光雷达在潮湿、高粉尘巷道中采集的原始点云,主要混入两类干扰:一是悬浮粉尘与水滴形成的近距密集噪点,它们在空间上随机散布、反射强度普遍偏低;二是巷道壁面水膜与煤泥造成的强度异常点,其距离正常但反射强度偏离同材质统计区间。若直接送入配准,这些点会污染法向估计与特征匹配,导致位姿解算抖动。因此预处理分两步:先按距离门限 + 反射强度门限做滤波,再按几何高度与法向把地面与侧壁分开,输出干净的地面点集与壁面点集。

滤波参数怎么定:距离与强度的双门限

设单帧点云为 P = {p_i},每点含 (x, y, z, intensity),雷达安装高度 h_mount(示例取 1.2 m),巷道断面近似矩形。滤波规则如下:

  • 距离门限:剔除 r_i < r_min 的近距粉尘团。示例 r_min = 0.8 m,因为该距离内多为镜头前悬浮颗粒与水滴。
  • 强度门限:粉尘与水滴回波弱,示例取 I_min = 25(0–255 归一化强度),低于该值判为噪点。
  • 统计离群剔除:对剩余点做 k 近邻平均距离检验,邻域 k = 10,均值距离超过 μ + 2σ 的点剔除,用于清理稀疏飞点。

地面分割采用“高度带 + 法向”联合判据:地面点满足 |z_i + h_mount| < d_ground(示例 d_ground = 0.15 m,即相对巷道底板高度带),且局部法向与竖直方向夹角 θ < 25°;侧壁点满足法向近似水平(与竖直方向夹角 > 65°)。这样可避免把斜坡底板误判为壁面。

原始单帧点云 粉尘 / 水滴噪点 壁面水膜强度异常 地面 + 侧壁 + 顶板 N ≈ 6.4 万点 距离 + 强度双门限 r_i ≥ 0.8 m I_i ≥ 25 剔除近距粉尘团 剔除弱回波水滴 k=10 邻域统计离群 μ+2σ 剔除飞点 局部法向估计 邻域半径 0.3 m PCA 拟合平面 输出法向 n_i 与竖直夹角 θ 高度带 + 法向联合分割 地面点集 |z + 1.2| < 0.15 m 且 θ < 25° 侧壁点集 θ > 65° 保留管道 / 支架结构 干净输入 → 后续配准 地面点集 + 壁面点集,噪点率下降 示例参数(需按现场标定) r_min = 0.8 m I_min = 25 k = 10 d_ground = 0.15 m h_mount = 1.2 m 法向邻域 0.3 m,θ 门限 25° / 65° 判据:滤波后噪点率 < 3% 视为合格

可运行的预处理实现(Python + NumPy)

下面代码自包含:生成一帧带粉尘噪点与壁面强度异常的模拟巷道点云,执行双门限滤波、统计离群剔除、法向估计与地面/侧壁分割,并打印各阶段点数与噪点率,便于验证参数是否合理。

import numpy as np

rng = np.random.default_rng(7)

# ---------- 1. 构造模拟巷道点云(示例数据,非实测) ----------
def make_frame(n_ground=20000, n_wall=20000, n_dust=3000, n_water=1500):
    # 地面:z = -1.2(雷达高1.2m,底板在下方),x 沿巷道 0~20m,y 宽 -2~2m
    gx = rng.uniform(0, 20, n_ground)
    gy = rng.uniform(-2, 2, n_ground)
    gz = -1.2 + rng.normal(0, 0.02, n_ground)
    gi = rng.normal(120, 12, n_ground)          # 地面反射较强
    ground = np.c_[gx, gy, gz, gi]

    # 侧壁:y = ±2,z 在 -1.2~1.0
    side = rng.choice([-2.0, 2.0], n_wall)
    wx = rng.uniform(0, 20, n_wall)
    wz = rng.uniform(-1.2, 1.0, n_wall)
    wi = rng.normal(95, 15, n_wall)
    wall = np.c_[wx, side + rng.normal(0, 0.02, n_wall), wz, wi]

    # 粉尘噪点:近距随机散布,强度低
    dx = rng.uniform(0, 1.0, n_dust)
    dy = rng.uniform(-1.5, 1.5, n_dust)
    dz = rng.uniform(-1.0, 1.0, n_dust)
    di = rng.uniform(5, 22, n_dust)
    dust = np.c_[dx, dy, dz, di]

    # 壁面水膜异常点:距离正常但强度异常低
    ax = rng.uniform(0, 20, n_water)
    ay = rng.choice([-2.0, 2.0], n_water)
    az = rng.uniform(-1.2, 1.0, n_water)
    ai = rng.uniform(8, 24, n_water)
    water = np.c_[ax, ay, az, ai]

    return np.vstack([ground, wall, dust, water])

pts = make_frame()
print(f"原始点数: {len(pts)}")

# ---------- 2. 距离 + 强度双门限滤波 ----------
xyz, inten = pts[:, :3], pts[:, 3]
r = np.linalg.norm(xyz, axis=1)
mask = (r >= 0.8) & (inten >= 25)
pts_f = pts[mask]
print(f"双门限后: {len(pts_f)}  剔除 {len(pts)-len(pts_f)}")

# ---------- 3. 统计离群剔除(k近邻平均距离) ----------
def statistical_outlier(p, k=10, std_ratio=2.0):
    from scipy.spatial import cKDTree
    tree = cKDTree(p[:, :3])
    d, _ = tree.query(p[:, :3], k=k + 1)
    mean_d = d[:, 1:].mean(axis=1)
    thr = mean_d.mean() + std_ratio * mean_d.std()
    return p[mean_d <= thr]

pts_f = statistical_outlier(pts_f)
print(f"离群剔除后: {len(pts_f)}")

# ---------- 4. 法向估计(PCA) ----------
def estimate_normals(p, radius=0.3):
    from scipy.spatial import cKDTree
    tree = cKDTree(p[:, :3])
    normals = np.zeros((len(p), 3))
    for i, q in enumerate(p[:, :3]):
        idx = tree.query_ball_point(q, radius)
        if len(idx) < 5:
            normals[i] = [0, 0, 1]
            continue
        nb = p[idx, :3] - p[idx, :3].mean(axis=0)
        _, _, vh = np.linalg.svd(nb, full_matrices=False)
        normals[i] = vh[-1]
    return normals

normals = estimate_normals(pts_f)
theta = np.degrees(np.arccos(np.clip(np.abs(normals[:, 2]), 0, 1)))  # 与竖直夹角

# ---------- 5. 高度带 + 法向联合分割 ----------
h_mount, d_ground = 1.2, 0.15
z_rel = pts_f[:, 2] + h_mount
ground_mask = (np.abs(z_rel) < d_ground) & (theta < 25)
wall_mask = theta > 65

ground_pts = pts_f[ground_mask]
wall_pts = pts_f[wall_mask]
print(f"地面点: {len(ground_pts)}  侧壁点: {len(wall_pts)}")

# ---------- 6. 噪点率评估 ----------
# 以“距地面/壁面理论位置超过 0.1m 且强度低于 30”近似统计残留噪点
residual = pts_f[(np.abs(pts_f[:, 2] + 1.2) > 0.1) &
                 (np.abs(np.abs(pts_f[:, 1]) - 2.0) > 0.1) &
                 (pts_f[:, 3] < 30)]
print(f"残留噪点率: {len(residual)/len(pts_f)*100:.2f}%")

运行后应看到:原始约 4.45 万点,双门限剔除近距粉尘与弱回波后显著下降,统计离群再清理少量飞点;地面点与侧壁点数量接近理论比例,残留噪点率通常可压到 3% 以下。若噪点率偏高,优先检查 I_min 是否过低或 r_min 是否偏小。

现场标定时,先采集一段无粉尘的静态帧统计地面与壁面强度分布,取壁面强度 5% 分位数作为 I_min 初值;再在粉尘段上微调,避免把真实弱反射壁面(如湿煤壁)误删。

结果判读与常见问题

现象可能原因处理
地面点大量丢失d_ground 过小或底板有坡度放宽到 0.2 m,或改用 RANSAC 拟合地平面
侧壁点混入地面法向估计邻域过大,壁面被平滑减小邻域半径至 0.2 m,重估法向
残留噪点率高I_min 偏低,水滴回波未滤除提高 I_min 至 30,或加距离-强度联合阈值
管道被误删管道强度低于门限对 r > 3 m 区域单独放宽强度门限

完成本步后,输出的 ground_pts 与 wall_pts 即为后续帧间配准的干净输入;地面点可用于估计底板平面约束,壁面点用于提取结构化特征。