任务需求:
对包含了x y z r g b六中信息的点云数据(txt)格式进行半径滤波,我的数据是按照S3DIS来制作的,之前查了很多资料发现都没有直接对txt格式进行操作的.直接见代码吧
代码
import numpy as np
from sklearn.neighbors import NearestNeighbors
import os
def radius_filter(points, radius, min_num):
# 对原始点云数据进行半径滤波,返回处理后的点的索引
neigh = NearestNeighbors(radius=radius)
neigh.fit(points)
indices = neigh.radius_neighbors(points, return_distance=False)
filtered_indices = []
for i, neighbors in enumerate(indices):
if len(neighbors) > min_num:
filtered_indices.append(i)
return points[filtered_indices, :], filtered_indices, np.concatenate(indices)
# 读取点云数据
# 定义输入和输出文件夹的路径
input_folder = ".."
output_folder = ".."
# 遍历输入文件夹中的所有子文件夹
for subdir, dirs, files in os.walk(input_folder):
# 构造输出子文件夹的路径
output_subdir = os.path.join(output_folder, subdir[len(input_folder)+1:])
# 遍历子文件夹中的所有txt文件
for filename in files:
if filename.endswith(".txt"):
print("正在处理")
# 构造输入和输出文件的路径
input_path = os.path.join(subdir, filename)
output_path = os.path.join(output_subdir, filename)
data = np.genfromtxt(input_path, delimiter=' ')
# 将点云数据分成点和颜色两部分
points = data[:, :3]
colors = data[:, 3:]
filtered_points, filtered_indices, indices = radius_filter(points, 0.2, 20)
filtered_colors = colors[filtered_indices, :]
# 将过滤后的点云数据和颜色数据合并
filtered_data = np.concatenate((filtered_points, filtered_colors), axis=1)
os.makedirs(output_subdir, exist_ok=True)
# 将处理后的点云数据保存到输出文件中
np.savetxt(output_path, filtered_data, delimiter=' ', fmt='%.6f %.6f %.6f %d %d %d')
其中input_folder 和output_folder需要自己来设置读取文件的路径和保存录取,代码可以自动根据读取文件夹中去寻找txt文件,处理后的文件会保存到output_folder,另外只需要指定最大的目录即可(参考S3DIS数据集),保存的output_folder文件夹会自动创建与读取路径中相同命名的子文件夹并保存对应的txt文件。同时可以修改radius_filter(points, 0.2, 20)中后两个参数来指定半径和邻近点的个数。
针对比较大的数据
以下是优化后的代码,主要采用分块读取文件来处理,防止点云数据过大造成内存溢出,这里我设置的块的大小是20w
import numpy as np
import pandas as pd
from sklearn.neighbors import NearestNeighbors
import os
import time
def radius_filter(points, radius, min_num):
# 对原始点云数据进行半径滤波,返回处理后的点的索引
neigh = NearestNeighbors(radius=radius)
neigh.fit(points)
indices = neigh.radius_neighbors(points, return_distance=False)
filtered_indices = []
for i, neighbors in enumerate(indices):
if len(neighbors) > min_num:
filtered_indices.append(i)
return points[filtered_indices, :], filtered_indices, np.concatenate(indices)
# 定义输入和输出文件夹的路径
input_folder = "..."
output_folder = "..."
#分块读取的块大小
chunk_size = 200000
#创建所有输出目录
for subdir, dirs, files in os.walk(input_folder):
output_subdir = os.path.join(output_folder, subdir[len(input_folder)+1:])
os.makedirs(output_subdir, exist_ok=True)
# 遍历子文件夹中的所有txt文件, 并进行处理
for filename in files:
if filename.endswith(".txt"):
input_path = os.path.join(subdir, filename)
output_path = os.path.join(output_subdir, filename)
#使用pandas分块读取点云数据
start_time = time.time()
reader = pd.read_csv(input_path, delimiter=' ', header=None, chunksize=chunk_size)
# 创建临时输出文件
temp_output_path = output_path + ".temp"
temp_output_file = open(temp_output_path, 'w')
#循环读取块,进行处理并将结果写入临时输出文件
for data in reader:
points = data.iloc[:, :3].values
colors = data.iloc[:, 3:].values
filtered_points, filtered_indices, indices = radius_filter(points, 0.2, 20)
filtered_colors = colors[filtered_indices, :]
#将过滤后的点云数据和颜色数据合并
filtered_data = np.concatenate((filtered_points, filtered_colors), axis=1)
#将处理后的点云数据保存到临时输出文件中
np.savetxt(temp_output_file, filtered_data, delimiter=' ', fmt='%.6f %.6f %.6f %d %d %d')
print(f"处理完毕: {temp_output_path}")
# 关闭临时输出文件
temp_output_file.close()
#合并去重结果,并删除临时文件
merged_data = pd.read_csv(temp_output_path, delimiter=' ', header=None).drop_duplicates().values
np.savetxt(output_path, merged_data, delimiter=' ', fmt='%.6f %.6f %.6f %d %d %d')
os.remove(temp_output_path)
print(f"文件 {output_path} 处理完毕, 用时:{time.time()-start_time:.2f}秒")