利用RANSAC进行地面点云的剔除
本文利用sklearn
中的RANSACRegressor
来对Kitti自动驾驶数据集中的点云数据进行地面数据剔除。本文主要分为四个部分:
- 点云数据读取与转换
- 高度滤波
- 点云剔除
- 结果可视化
代码中需要用到的库如下:
import numpy as np
import os
import struct
import open3d as o3d
import numpy as np
from sklearn.linear_model import RANSACRegressor
from sklearn.linear_model import LinearRegression
点云数据的读取与转换
本文定义read_velodyne_bin(path)
函数来读取Kitti数据集中的.bin二进制文件,函数先对原始数据进行读取,然后对数据进行解码并将数据转化为np.array,具体的代码实现如下:
def read_velodyne_bin(path):
pc_list = []
with open(path, 'rb') as f:
content = f.read()
pc_iter = struct.iter_unpack('ffff', content)
for idx, point in enumerate(pc_iter):
pc_list.append([point[0], point[1], point[2]])
return np.asarray(pc_list, dtype=np.float32)
对该函数进行测试,代码如下,本文将Kitti数据集中的一帧取出,放置于当前目录下:
points=read_velodyne_bin('./000000.bin')
pc = o3d.geometry.PointCloud()
pc.points = o3d.utility.Vector3dVector(points)
o3d.visualization.draw_geometries([pc])
测试结果如下:
高度滤波
先用可以提前获取的高度信息,粗粒度的剔除一些无关的点云数据, 这里使用-0.57作为分割值来对点云数据进行切片处理(可以多尝试几个数据,也可以得到一些关于数据的统计信息来设置初值),代码如下:
points=np.asarray([ data for data in points_f if data[2]<-0.57])
points_idx=np.asarray([ data_idx for data_idx, data in enumerate(points_f) if data[2]<-0.57])
pc = o3d.geometry.PointCloud()
pc.points = o3d.utility.Vector3dVector(points)
o3d.visualization.draw_geometries([pc])
切片处理后的点云数据如下图所示:
点云剔除
本文采用RANSAC聚类,通过计算点到拟合平面的距离来对地面点云进行剔除,具体的代码如下:
# 提取特征(X)和目标变量(y)
X = points[:, :2] # 使用前两个坐标作为特征
y = points[:, 2] # 使用第三个坐标作为目标变量
# 创建基本估计器
base_estimator = LinearRegression()
# 创建RANSACRegressor
ransac = RANSACRegressor(estimator=base_estimator, min_samples=10, residual_threshold=0.4, random_state=42)
# 拟合数据
ransac.fit(X, y)
inlier_mask=ransac.inlier_mask_
outlier_mask=np.logical_not(inlier_mask)
最后对分割结果进行可视化处理:
del_idx=points_idx[inlier_mask]
filted_points=np.delete(points_f,del_idx,axis=0)
#filted_points=[f_p for i, f_p in enumerate(points_f) if i not in del_idx ]
pc = o3d.geometry.PointCloud()
pc_g=o3d.geometry.PointCloud()
pc_g.points=o3d.utility.Vector3dVector(points[inlier_mask])
pc_g.paint_uniform_color([0,0,1])
pc.points = o3d.utility.Vector3dVector(filted_points)
pc.paint_uniform_color([0,1,0])
o3d.visualization.draw_geometries([pc,pc_g])
最后的效果图如下,其中蓝色为地面,绿色为其他部分: