I wish to filter a pointcloud, loaded with opend3d
, as efficiently as possible.
Currently, I perform a downsampling of the points before making a mesh out of them and using .contains
on an inclusion volume mesh I did manually. Something like this:
def load_pointcloud(self, pointcloud_path):
# Load Pointcloud
print('target_pointcloud', pointcloud_path)
self.pointcloud_path = pointcloud_path
pcd = o3d.io.read_point_cloud(pointcloud_path)
downpcd = pcd.voxel_down_sample(voxel_size=0.02)
cl, ind = downpcd.remove_statistical_outlier(nb_neighbors=20,
std_ratio=2.0)
downpcd = downpcd.select_by_index(ind)
pcd_points = np.asarray(downpcd.points, dtype=np.float32)
self.verts = torch.from_numpy(pcd_points)
self.verts = self.verts.to(device)
# We construct a Meshes structure for the target mesh
self.pointcloud_points = Pointclouds(points=[self.verts])
self.points = pcd_points
self.inclusion_pointcloud()
def inclusion_pointcloud(self):
vetices_in_mesh_states = self.mesh_inclusion.contains(self.points)
vetices_in_mesh = self.points[vetices_in_mesh_states == True]
# Creating cropped point cloud
cropped_pc = o3d.geometry.PointCloud()
cropped_pc.points = o3d.utility.Vector3dVector(vetices_in_mesh)
cropped_pc.paint_uniform_color([0,0,0])
self.points = np.asarray(cropped_pc.points, dtype=np.float32)
self.verts = torch.from_numpy(self.points)
self.verts = self.verts.to(device)
self.pointcloud_points = Pointclouds(points=[self.verts])
self.pc_mesh = trimesh.Trimesh(vertices=self.points)
What I was thinking in doing was to, after the downsampling, mask away points on X, Y, and Z, and then making a mesh to use .contains
again in the same inclusion volume. I thought that this would reduce the .contains
computation and run faster, and it kind of does, but is a marginal reduction, like 10 or 15ms, sometimes less. Something like this:
def new_load_pointcloud(self, pointcloud_path):
# Load Pointcloud
print('target_pointcloud', pointcloud_path)
self.pointcloud_path = pointcloud_path
pcd = self.trim_cloud(pointcloud_path)
downpcd = pcd.voxel_down_sample(voxel_size=0.02)
cl, ind = downpcd.remove_statistical_outlier(nb_neighbors=20,
std_ratio=2.0)
downpcd = downpcd.select_by_index(ind)
pcd_points = np.asarray(downpcd.points, dtype=np.float32)
self.verts = torch.from_numpy(pcd_points)
self.verts = self.verts.to(device)
# We construct a Meshes structure for the target mesh
self.pointcloud_points = Pointclouds(points=[self.verts])
self.points = pcd_points
self.inclusion_pointcloud()
def trim_cloud(self, pointcloud_path):
# pcd = o3d.io.read_point_cloud(pointcloud_path)
pcd_clean = o3d.io.read_point_cloud(pointcloud_path)
# X Axis
points = np.asarray(pcd_clean.points)
mask_x_1 = points[:,0] > -0.4
mask_x_2 = points[:,0] < 0.4
# Y Axis
mask_y_1 = points[:,1] > -1.3
mask_y_2 = points[:,1] < 0.9
# Z Axis
mask_z_1 = points[:,2] < 0.3 # Closer to floor
mask_z_2 = points[:,2] > -0.1 # Clooser to ceiling
mask_x = np.logical_and(mask_x_1, mask_x_2) # Along table's wide
mask_y = np.logical_and(mask_y_1, mask_y_2) # Along table's longitude
mask_z = np.logical_and(mask_z_1, mask_z_2) # Along table's height
mask = np.logical_and(mask_x, mask_y, mask_z)
pcd_clean.points = o3d.utility.Vector3dVector(points[mask])
return pcd_clean
def inclusion_pointcloud(self):
vetices_in_mesh_states = self.mesh_inclusion.contains(self.points)
vetices_in_mesh = self.points[vetices_in_mesh_states == True]
# Creating cropped point cloud
cropped_pc = o3d.geometry.PointCloud()
cropped_pc.points = o3d.utility.Vector3dVector(vetices_in_mesh)
cropped_pc.paint_uniform_color([0,0,0])
self.points = np.asarray(cropped_pc.points, dtype=np.float32)
self.verts = torch.from_numpy(self.points)
self.verts = self.verts.to(device)
self.pointcloud_points = Pointclouds(points=[self.verts])
self.pc_mesh = trimesh.Trimesh(vertices=self.points)
I think you are using too much nb_neighbors for the filter. Try less points, like 6 or 10, and a better threshold, like 1.0 or even 0.5. Here is the same filter on MATLAB documentation https://www.mathworks.com/help/vision/ref/pcdenoise.html , standard value for the threshold is 1.0 and for the knn is 6. You can also try the Radius Outlier Removal or the median filter: https://www.mathworks.com/help/lidar/ref/pcmedian.html
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.