MVSNet为什么要进行重投影?
将参考图像通过深度估计和变换矩阵投影到每个源视图上,再和参考视图进行对比计算-----光度一致性损失
但是在重投影的过程中,可能会因为源图像对应像素被遮挡或者超出源图像边界导致某些像素重投影失败
将参考点云在源视角下进行投影,然后再回投到参考视角的过程
图解:
1. 输入输出
输入:
depth_ref:参考视角的深度图(源视角投影到参考视角之前的深度图)
intrinsics_ref:参考视角的相机内参
extrinsics_ref:参考视角的相机外参
depth_src:源视角的深度图
intrinsics_src:源视角的相机内参
extrinsics_src:源视角的相机外参
输出:
depth_reprojected:重映射的深度
x_reprojected, y_reprojected:重映射后的参考视角下的像素坐标
x_src, y_src:参考视角映射到源视角下的像素坐标
2. 过程
分两步:
step1.将参考视角的像素投影到源视角上得到源视角的点
1/得到参考视角下各个像素的坐标x_ref, y_ref
2/像素坐标->参考视角的三维点云坐标xyz_ref
3/参考视角的三维点云坐标 映射 -> 源视角下的三维点云坐标xyz_src
4/源视角下的三维点云坐标 -> 源视角下的三维像素坐标K_xyz_src
源视角三维像素坐标 -> 源视角二维像素坐标xy_src
step2.使用源视角的深度估计(sampled_depth_src)来重新投影源视角的点,得到重投影后的参考视角的点
1/找到上一步映射到源视角下的的像素坐标x_src,y_src
2/将源视角下的深度图根据源视角像素坐标重新采样得到源视角下的深度估计 sampled_depth_src
3/将源视角下的像素坐标 -> 源视角下的三维点云坐标xyz_src
4/源视角下的三维点云坐标 重映射 ->参考视角下的点云坐标 xyz_reprojected
5/参考视角下的点云坐标的第三维度 ->深度, 前两个维度-> 点云坐标
【参考视角下】点云坐标 -> 像素坐标 -> 归一化x_reprojected, y_reprojected
3. code
def reproject_with_depth(depth_ref, intrinsics_ref, extrinsics_ref, depth_src, intrinsics_src, extrinsics_src):
width, height = depth_ref.shape[1], depth_ref.shape[0] # 参考视角深度图的宽和高
## step1. project reference pixels to the source view
# 参考视角的x,y
x_ref, y_ref = np.meshgrid(np.arange(0, width), np.arange(0, height)) # 二维矩阵
x_ref, y_ref = x_ref.reshape([-1]), y_ref.reshape([-1]) # 压缩为一维
# reference 3D space 参考视角的3D空间
# 将(参考视角下的像素坐标和深度值)通过(相机内参的逆)转换为参考视角下的三维点云坐标(xyz_ref),xyz_ref是一个3行N列的矩阵,每一列对应一个像素的三维空间坐标(x, y, depth)。
xyz_ref = np.matmul(np.linalg.inv(intrinsics_ref),
np.vstack((x_ref, y_ref, np.ones_like(x_ref))) * depth_ref.reshape([-1]))
# source 3D space 源视角的3D空间
# 将参考视角下的三维点云坐标(xyz_ref)映射到源视角下的坐标系,得到源视角下的三维点云坐标(xyz_src)
xyz_src = np.matmul(np.matmul(extrinsics_src, np.linalg.inv(extrinsics_ref)),
np.vstack((xyz_ref, np.ones_like(x_ref))))[:3]
# source view x, y 源视角的x, y
# 将源视角下的三维点云坐标xyz_src乘以源视角的相机内参intrinsics_src,得到在源视角下的像素坐标K_xyz_src(x, y, depth)
K_xyz_src = np.matmul(intrinsics_src, xyz_src) # 源视角下的像素坐标
xy_src = K_xyz_src[:2] / K_xyz_src[2:3] # 对源视角下的像素坐标前两维度/第三维度(深度)->源视角下的归一化的像素坐标(x/depth, y/depth, depth)
## step2. reproject the source view points with source view depth estimation
# 取前两维得到源视角下的像素坐标
x_src = xy_src[0].reshape([height, width]).astype(np.float32)
y_src = xy_src[1].reshape([height, width]).astype(np.float32)
# 将源视角下的深度图depth_src根据映射后的源视角下的像素坐标x_src和y_src进行重新采样,得到重采样后的深度图
# 目的:为了使源视图深度值与新的目标像素位置对应起来
sampled_depth_src = cv2.remap(depth_src, x_src, y_src, interpolation=cv2.INTER_LINEAR)
# source 3D space 源视角的3D空间
# NOTE:这里使用采样得到的源视角深度【sampled_depth_src】来进行重投影
# 将源视角下的像素坐标转化为源视角下的三维点云坐标
xyz_src = np.matmul(np.linalg.inv(intrinsics_src),
np.vstack((xy_src, np.ones_like(x_ref))) * sampled_depth_src.reshape([-1]))
# reference 3D space-参考视角的3D空间
# 将源视角下的三维点云坐标重映射回参考视角,得到参考视角点云坐标
xyz_reprojected = np.matmul(np.matmul(extrinsics_ref, np.linalg.inv(extrinsics_src)),
np.vstack((xyz_src, np.ones_like(x_ref))))[:3]
# source view x, y, depth-源视角的 x, y, 深度
depth_reprojected = xyz_reprojected[2].reshape([height, width]).astype(np.float32) # 将参考视角点云坐标的第三行提取出来得到重映射的深度
# 将参考视角下的三维点云坐标乘以参考视角的相机内参,得到在参考视角下的像素坐标
K_xyz_reprojected = np.matmul(intrinsics_ref, xyz_reprojected) # 重映射参考视角的像素坐标
xy_reprojected = K_xyz_reprojected[:2] / K_xyz_reprojected[2:3] # 归一化处理,将前两个维度【像素坐标】除以第三个维度【深度】,xy_reprojected保存了在参考视角下归一化的像素坐标
x_reprojected = xy_reprojected[0].reshape([height, width]).astype(np.float32)
y_reprojected = xy_reprojected[1].reshape([height, width]).astype(np.float32)
return depth_reprojected, x_reprojected, y_reprojected, x_src, y_src