要将mesh转换为深度图,有两种思路:
- 遍历mesh的每一个面片,将每个面片往图像上投影,将投影覆盖到的区域深度利用面片顶点的深度进行插值计算。
- 获取图像上所有像素对应的光线,将这些光线与mesh进行求交运算,获取交点的坐标,进而求解交点到像素的距离,即为深度值。
这里介绍的是第2种方法 。使用python语言,基于mesh处理包trimesh(官网)进行计算。此外,由于代码使用了pyembree进行加速,所以需要同时安装pyembree包。这两个包的安装命令:
pip install pyembree trimesh
转换代码如下:
import numpy as np
import trimesh
from trimesh.ray.ray_pyembree import RayMeshIntersector
# 获取图像所有像素所对应的光线起点和方向
def get_rays(W, H, fx, fy, cx, cy, c2w_R, c2w_t, center_pixels):
# 获取图像所有像素中心点
j, i = np.meshgrid(np.arange(H, dtype=np.float32), np.arange(W, dtype=np.float32))
if center_pixels:
i = i.copy() + 0.5
j = j.copy() + 0.5
# 计算相机坐标系下的光线方向,(H, W, 3)
directions = np.stack([(i - cx) / fx, (j - cy) / fy, np.ones_like(i)], -1)
directions /= np.linalg.norm(directions, axis=-1, keepdims=True)
# 获取光线起点,起点均为相机在世界坐标系下坐标
rays_o = np.expand_dims(c2w_t,0).repeat(H*W, 0)
# 获取光线方向
rays_d = directions @ c2w_R.T # (H, W, 3)
rays_d = (rays_d / np.linalg.norm(rays_d, axis=-1, keepdims=True)).reshape(-1,3)
return rays_o, rays_d
# mesh转深度图
# 其中R和t是相机在世界坐标系下的位姿,即c2w
def mesh2depth(meshpath, W, H, fx, fy, cx, cy, R, t, outdir):
# 读取mesh文件
mesh = trimesh.load(meshpath)
# 获取光线原点、方向、对应像素的坐标
rays_o, rays_d = get_rays(W, H, f, f, cx, cy, c2w_R, c2w_t, True)
coords = np.array(list(np.ndindex(H,W))).reshape(H,W,-1).transpose(1,0,2).reshape(-1,2)
# 使用trimesh包进行ray-mesh求交计算
# 这里的RayMeshIntersector()是使用pyembree进行加速
# 输出points是交点坐标列表,index_ray是有交点的ray的id,_是相交的面片id,我们不需要用到
points, index_ray, _ = RayMeshIntersector(mesh).intersects_location(rays_o, rays_d, multiple_hits=False)
# 如下是两种计算深度的方式,通常使用的是第二种,即相当于每个像素的z值;
# 而第一种计算的是交点沿着光线到发射原点(光心)的距离
# depth = trimesh.util.diagonal_dot(points - rays_o[0], rays_d[index_ray]) # 计算交点到相机中心的距离
depth = (points @ w2c_R.T + w2c_t)[:,-1] # 将交点转换到相机坐标系下,取其z值
# 通过光线id获得其像素坐标
pixel_ray = coords[index_ray]
# 创建深度图矩阵,并进行对应赋值,没值的地方为nan,即空值
depthmap = np.full([H,W], np.nan)
depthmap[pixel_ray[:, 0], pixel_ray[:, 1]] = depth
# 保存深度图,格式默认为npy
np.save(outdir, depthmap)
这里将深度图保存为npy格式的,是方便使用深度图进行后续的操作,只要np.load进来即是ndarray了。而如果要可视化深度图,或者想把深度图转换为jpg图片的话,可以参考python读取并可视化npy格式的深度图文件以及将其保存为jpg图片的方法。