''' 获取Mesh的深度图 required: - open3d - numpy - numba ''' import open3d as o3d import numpy as np from numba import njit @njit def _process_all_points(Z, width, height, cx, cy, fx, fy, c2w): """JIT优化的所有点处理函数""" # 手动创建像素网格(替代np.meshgrid) u = np.zeros((height, width), dtype=np.float64) v = np.zeros((height, width), dtype=np.float64) for y in range(height): for x in range(width): u[y, x] = x v[y, x] = y # 创建输出数组 Z_all = np.zeros_like(Z) # 手动处理有效点 for y in range(height): for x in range(width): if Z[y, x] > 0 and Z[y, x] < 1e9 and not np.isnan(Z[y, x]): Z_all[y, x] = Z[y, x] else: Z_all[y, x] = -10000 # 计算所有点的3D坐标 X_all = (u - cx) * Z_all / fx Y_all = (v - cy) * Z_all / fy # 创建齐次坐标 points_3d = np.zeros((height * width, 4)) points_3d[:, 0] = X_all.reshape(-1) points_3d[:, 1] = Y_all.reshape(-1) points_3d[:, 2] = Z_all.reshape(-1) points_3d[:, 3] = 1.0 # 坐标变换 return points_3d @ c2w.T @njit def _process_valid_points(Z, width, height, cx, cy, fx, fy, c2w): """JIT优化的有效点处理函数""" # 首先计算有效点的数量 valid_count = 0 for y in range(height): for x in range(width): if Z[y, x] > 0 and Z[y, x] < 1e9 and not np.isnan(Z[y, x]): valid_count += 1 # 创建输出数组 X_valid = np.zeros(valid_count) Y_valid = np.zeros(valid_count) Z_valid = np.zeros(valid_count) # 填充有效点数据 idx = 0 for y in range(height): for x in range(width): if Z[y, x] > 0 and Z[y, x] < 1e9 and not np.isnan(Z[y, x]): Z_valid[idx] = Z[y, x] X_valid[idx] = (x - cx) * Z_valid[idx] / fx Y_valid[idx] = (y - cy) * Z_valid[idx] / fy idx += 1 # 创建齐次坐标 points_3d = np.zeros((valid_count, 4)) points_3d[:, 0] = X_valid points_3d[:, 1] = Y_valid points_3d[:, 2] = Z_valid points_3d[:, 3] = 1.0 # 坐标变换 return points_3d @ c2w.T def get_world_points(depth_map: o3d.geometry.Image, K: np.ndarray, c2w: np.ndarray, all_point: bool = False) -> np.ndarray: ''' 获取深度图对应的世界坐标点云 param: depth_map: 深度图 K: 相机内参矩阵 c2w: 相机坐标系到世界坐标系的变换矩阵 all_point: 是否返回所有点(包括无效点) return: np.ndarray: 点云坐标(世界坐标系) - 当all_point=False时:只包含有效深度值的点云 - 当all_point=True时:包含所有点的点云,无效点深度值设为10000 ''' # 转换为numpy数组 Z = np.asarray(depth_map) height, width = Z.shape # 获取内参 fx, fy = K[0, 0], K[1, 1] cx, cy = K[0, 2], K[1, 2] # 确保数据类型兼容性(Numba要求) Z = Z.astype(np.float64) c2w = c2w.astype(np.float64) if all_point: return _process_all_points(Z, width, height, cx, cy, fx, fy, c2w) else: return _process_valid_points(Z, width, height, cx, cy, fx, fy, c2w)