Spaces:
Running
on
Zero
Running
on
Zero
| import numpy as np | |
| import open3d as o3d | |
| def depth2pcd(depth, intrinsic, color=None, input_mask=None, ret_pcd=False): | |
| """ | |
| Convert a depth map into a 3D point cloud. | |
| Args: | |
| depth (np.ndarray): (H, W) depth map in meters. | |
| intrinsic (np.ndarray): (3, 3) camera intrinsic matrix. | |
| color (np.ndarray, optional): (H, W, 3) RGB image aligned with the depth map. | |
| input_mask (np.ndarray, optional): (H, W) boolean mask indicating valid pixels. | |
| ret_pcd (bool, optional): If True, returns an Open3D PointCloud object; | |
| otherwise returns NumPy arrays. | |
| Returns: | |
| - If ret_pcd=True: returns `o3d.geometry.PointCloud()` | |
| - Otherwise: returns (N, 3) point coordinates and (N, 3) color arrays. | |
| """ | |
| H, W = depth.shape | |
| x, y = np.meshgrid(np.arange(W), np.arange(H)) | |
| xx, yy = x.reshape(-1), y.reshape(-1) | |
| zz = depth.reshape(-1) | |
| # Create a valid pixel mask | |
| mask = np.ones_like(zz, dtype=bool) | |
| if input_mask is not None: | |
| mask &= input_mask.reshape(-1) | |
| # Form homogeneous pixel coordinates | |
| pixels = np.stack([xx, yy, np.ones_like(xx)], axis=1) | |
| # Back-project pixels into 3D camera coordinates | |
| points = pixels * zz[:, None] | |
| points = np.dot(points, np.linalg.inv(intrinsic).T) | |
| # Keep only valid points | |
| points = points[mask] | |
| # Process color information | |
| if color is not None: | |
| color = color.astype(np.float32) / 255.0 | |
| colors = color.reshape(-1, 3)[mask] | |
| else: | |
| colors = None | |
| # Return Open3D point cloud or NumPy arrays | |
| if ret_pcd: | |
| pcd = o3d.geometry.PointCloud() | |
| pcd.points = o3d.utility.Vector3dVector(points) | |
| if colors is not None: | |
| pcd.colors = o3d.utility.Vector3dVector(colors) | |
| return pcd | |
| else: | |
| return points, colors |