研究背景以及基本的环境部分请见第三届‘悉灵杯’-基于MV-EB435i-A相机的室内3D语义感知课题研究进展(一)
color_bgr = image.reshape(-1, 3).astype(np.float32)
color_rgb = color_bgr[:, [2, 1, 0]]
point = np.hstack([point, color_rgb])
mask = np.any(point[:, :3] != 0, axis=1)
filtered_point = point[mask]
scaled_point = apply_uniform_sampling(filtered_point, 20000)
scaled_point = normalize_point_cloud(scaled_point)
np.save(os.path.join(save_dir, 'point', f"{stData.nFrameNum}.npy"), scaled_point)
异源数据融合获取有色点云的过程可以概述如下:首先,将图像数据从 BGR 格式转换为 RGB 格式,并将其展平为二维数组的形式。然后,将转换后的颜色信息与点云坐标合并,形成带有颜色属性的点云数据。通过创建掩码过滤掉无效的零坐标点,仅保留有效点云。接着,应用均匀采样方法对点云进行降采样,减少点数以便处理,并对点云数据进行归一化处理,以适应模型输入。最后,将处理后的有色点云数据保存为 .npy
文件,便于后续的使用和分析。这个过程结合了图像和点云数据的优势,使得每一个点不仅有空间坐标,还包含颜色信息,从而提升了点云的表达能力和可视化效果。
def normalize_point_cloud(point_cloud, range_min=-1, range_max=1):
xyz = point_cloud[:, :3]
min_vals_xyz = np.min(xyz, axis=0)
max_vals_xyz = np.max(xyz, axis=0)
max_range = np.max(max_vals_xyz - min_vals_xyz)
centers_xyz = (min_vals_xyz + max_vals_xyz) / 2.0
normalized_xyz = (xyz - centers_xyz) / max_range
normalized_xyz = normalized_xyz * (range_max - range_min) / 2.0 + (range_max + range_min) / 2.0
rgb = point_cloud[:, 3:]
normalized_point_cloud = np.hstack([normalized_xyz, rgb])
return normalized_point_cloud
def apply_uniform_sampling(pcd, number_of_points):
if number_of_points >= pcd.shape[0]:
print("返回原点云")
return pcd
step = pcd.shape[0] // number_of_points
indices = np.arange(0, pcd.shape[0], step)
if len(indices) > number_of_points:
indices = indices[:number_of_points]
sampled_pcd = pcd[indices]
return sampled_pcd
首先,提取点云的XYZ坐标,并计算每个坐标轴上的最小值和最大值。然后,计算坐标轴上的最大范围,并确定点云的中心位置。接下来,将点云的每个坐标减去中心位置后,按最大范围进行缩放,使其在目标范围(默认是-1到1)内以适配模型计算。最后,将处理后的坐标与原始的颜色信息(RGB)合并,返回归一化的点云数据。下采样部分则是使用简单的均匀采样,根据模型输入选取,也不会丢失太多信息。
内参矫正:
def adjust_intrinsic(intrinsics, original_dim, new_dim):
scale_x = new_dim[0] / original_dim[0]
scale_y = new_dim[1] / original_dim[1]
adjusted_intrinsics = intrinsics.copy()
adjusted_intrinsics[0, 0] *= scale_x
adjusted_intrinsics[1, 1] *= scale_y
adjusted_intrinsics[0, 2] *= scale_x
adjusted_intrinsics[1, 2] *= scale_y
return adjusted_intrinsics
对于摄像头采集数据与模型输入数据不匹配问题,对数据进行缩放以适配本文使用的ESAM深度学习模型,对于参数也需要进行相应的调整。
ICP配准:
def register_point_clouds(source, target, voxel_size):
"""使用ICP算法配准点云"""
source_down = source.voxel_down_sample(voxel_size)
target_down = target.voxel_down_sample(voxel_size)
source_down.estimate_normals(o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))
target_down.estimate_normals(o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))
threshold = voxel_size * 1.5
result_icp = o3d.pipelines.registration.registration_icp(
source_down, target_down, threshold, np.identity(4),
o3d.pipelines.registration.TransformationEstimationPointToPoint())
source.transform(result_icp.transformation)
return source
对于多视角配准中的表面重建,使用ICP(迭代最近点)算法对源点云和目标点云进行配准。首先,分别对两个点云进行体素降采样以简化计算量,然后估计它们的法向量。接着,定义一个基于体素大小的阈值,并使用ICP算法计算源点云相对于目标点云的最佳变换矩阵。最后,将计算得到的变换应用于源点云,使其与目标点云对齐,从而实现多视角下的表面重建。
下面是具体数据格式处理的形式说明,便于理解:
imge:
shape: (640, 480, 3)
detype: uint8
depth:
shape: (640, 480, 1)
detype: ufloat16
pose:
shape: (4, 4)
detype: float32
point:
shape: (20000, 6) #(点云数,xyzrgb)
detype: float32
point_xyz:
min: -1
max: 1
point_rgb:
min: 0
max: 255
合成ply:
shape: (500000, 6) #(点云数,xyzrgb)
detype: float32
min: -1
max: 1