python 深度图转点云

import numpy as np
def depth2xyz(depth_map,depth_cam_matrix,flatten=False,depth_scale=1000):
    fx,fy = depth_cam_matrix[0,0],depth_cam_matrix[1,1]
    cx,cy = depth_cam_matrix[0,2],depth_cam_matrix[1,2]
    h,w=np.mgrid[0:depth_map.shape[0],0:depth_map.shape[1]]
    z=depth_map/depth_scale
    x=(w-cx)*z/fx
    y=(h-cy)*z/fy
    xyz=np.dstack((x,y,z)) if flatten==False else np.dstack((x,y,z)).reshape(-1,3)
    #xyz=cv2.rgbd.depthTo3d(depth_map,depth_cam_matrix)
    return xyz

if __name__ == '__main__': 
    # 随便生成一个 分辨率为(720, 1280) -> (高为720, 宽为1280)的深度图, 注意深度图shape为(720, 1280)即深度图为单通道, 维度为2
    #而不是类似于shape为(720, 1280, 3)维度为3的这种
    depth_map = np.random.randint(0,10000,(720, 1280)) 

    depth_cam_matrix = np.array([[540, 0,  640],
                                 [0,   540,360],
                                 [0,   0,    1]])
    pc = depth2xyz(depth_map, depth_cam_matrix)
    pc_flatten = pc.reshape(-1, 3) # 等价于 pc = depth2xyz(depth_map, depth_cam_matrix, flatten=True)


    '''
    ################### 相机测距 ##################

    置 flatten=False 此时的pc是具有二维信息的 既shape为(720, 1280, 3) 否则为(720 * 1280, 3)
    
    此时 rgb 图片和点云的shape是一样的, 都为(720, 1280, 3)
    
    假设此时欲想测图片中的一个箱子的在真实世界中的长度, 箱子长边的一角a在rgb图片中的像素坐标为 (500, 100) -> (纵坐标, 横坐标), 长边的另一角b的像素坐标为(600, 200) -> (纵坐标, 横坐标)
    则a, b两点在 pc 中的 点云xyz坐标就是已知的, 因此此时只需求取a, b两点对应的xyz坐标的欧氏距离就是该箱子的长度
    notes: 相机测距如果想测得准则对深度相机的精度要求比较高, 如果深度相机精度不高 测出来的长度会十分糟糕(在depth2xyz中可以看出xy的计算均与z有关), 本人在realense 435, 415, 515 上使用过测距功能, 精度上 515 > 415 > 435, 因此测距功能 515 > 415 > 435

    当然 工业级深度相机的精度大部分是要远高于realsense这类消费级深度相机的, 价钱也更贵一些
    代码如下:

    a = pc[500, 100]
    b = pc[600, 200]
    ax, ay, az = a
    bx, by, bz = b
    # 此时 distance 就是箱子的长度
    distance = ((ax - bx) ** 2 + (ay - by) ** 2 + (az - bz) ** 2) ** 0.5
    # distance = np.linalg.norm(a - b)
    '''
    

输入参数:

1. depth_map: 深度图, 个人采用realsense D415, 采集出来的depth_map为uint16;

2. depth_cam_matrix: 深度相机内参矩阵, 应为二维矩阵, 并沿用以下格式

    [[ fx, 0, cx],

     [ 0, fy, cy],

     [ 0,  0,  1]]

3. flatten(bool) : 是否铺平, 如为False则保持二维信息 shape (H, W, 3),  为True则铺平点云 shape (H * W, 3), 其中 H, W为深度图的 高与宽, 若铺平则与 cv2.rgbd.depthTo3d(depth_map,depth_cam_matrix)结果相同

4. depth_scale: 深度缩放因子,一般为1000, 指的是毫米到米的变化, 如realsense采集出来的depth_map单位是毫米, 部分相机比较特殊depth_scale 可以到相机文档中找到

输出参数:

xyz : 点云

-----------------------------------补充----------------------------------

有被问到几个问题, 我额外开了几个博客回答.

1. 单个或多个像素坐标 到 点云坐标的变换

见 python 像素坐标转点云坐标_tycoer的博客-CSDN博客

2. 点云从相机坐标系到世界坐标系的变换 或者 点云从世界坐标系到相机坐标系的变换

见 python 点云从相机坐标系到世界坐标系/ 世界坐标系到相机坐标系下的变换_tycoer的博客-CSDN博客

3. 相机测距

最典型的就是苹果手机上的相机测距功能. 这要求相机需带有同时载有彩色相机和深度相机(典型如 Realsense), 见代码

你可能感兴趣的:(python,开发语言)