【MLP-BEV(7)】深度的计算。针孔相机和鱼眼相机对于深度depth的采样一个是均匀采样,一个是最大深度均匀采样

发布于:2024-07-02 ⋅ 阅读:(21) ⋅ 点赞:(0)

1.1 问题提出

针孔相机和鱼眼相机的投影模型和畸变模型不一样,如果对鱼眼的模型不太了解可以到我的这篇博客【鱼眼镜头11】Kannala-Brandt模型和Scaramuzza多项式模型区别,哪个更好?,以及这个系列看看。

针孔相机可以对于深度depth的采样一个是均匀采样,鱼眼来说,一个是最大深度均匀采样合适。

1.1 看看DD3D 的深度是怎么处理的

在3d head 中输出了深度,看这个代码

box3d_quat, box3d_ctr, box3d_depth, box3d_size, box3d_conf, dense_depth = self.fcos3d_head(features)

特征x经过 box3d_tower 卷积层后输出

box3d_tower_out = self.box3d_tower(features)
depth = self.box3d_depth[_l](box3d_tower_out)

而这个box3d_tower就是一群3x3卷积

box3d_tower.append(
                Conv2d(
                    in_channels,
                    in_channels,
                    kernel_size=3,
                    stride=1,
                    padding=1,
                    bias=norm_layer is None,
                    norm=norm_layer,
                    activation=F.relu
                )
            )

得到后得到深度

        pixel_size = torch.norm(torch.stack([inv_intrinsics[:, 0, 0], inv_intrinsics[:, 1, 1]], dim=-1), dim=-1)
        depth = depth / (pixel_size * scale_depth_by_focal_lengths_factor)

与相机的内参(intrinsics)和深度图(depth map)的处理有关。
这两行代码的目的是根据相机的焦距和某个比例因子来调整深度图的值。这在计算机视觉和3D重建等任务中是很常见的操作。

  • inv_intrinsics: 这应该是一个表示相机内参逆矩阵的Tensor。在相机标定中,内参矩阵通常是一个3x3的矩阵,包含了焦距(fx, fy)、主点(cx, cy)和可能的扭曲因子等。但是在这里,我们只关心对角线元素,即焦距的倒数(假设fx和fy已经被取倒数)。
  • torch.stack([inv_intrinsics[:, 0, 0], inv_intrinsics[:, 1, 1]], dim=-1): 这将逆内参矩阵的第一行第一列和第二行第二列的元素(即fx和fy的倒数)沿着最后一个维度(dim=-1)堆叠成一个新的Tensor。结果是一个形状为[batch_size, 2]的Tensor,其中batch_sizeinv_intrinsics的第一个维度的大小。
  • torch.norm(..., dim=-1): 这计算了沿着最后一个维度(dim=-1)的范数。但是,由于我们堆叠的是两个值(即两个焦距的倒数),实际上计算的是这两个值的L2范数,也就是它们的平方根之和(但在这个特殊情况下,由于只有两个正数,L2范数就是它们的几何平均值)。但是,因为这里两个数都是正数并且只是简单的堆叠,所以实际上torch.norm在这里计算的是这两个值的平方根的和,这与直接取它们的平均值(或者只是取它们的和,如果后续操作是除法)在效果上可能差别不大。但几何平均值或平方根的和可能用于平滑或归一化目的。
  • pixel_size: 最终得到的Tensor包含了每个图像或图像批次的“像素大小”的某种度量,这个度量是基于焦距的倒数来计算的。
  • depth: 这是一个表示深度图的Tensor,其中每个值可能代表图像中对应像素的真实世界深度(或某种与深度相关的量度)。
  • pixel_size * scale_depth_by_focal_lengths_factor: 这部分计算了每个像素的“大小”与某个比例因子scale_depth_by_focal_lengths_factor的乘积。这个比例因子可能是用于根据焦距来缩放或调整深度值的。
  • depth / ...: 最后,原始的深度图被这个乘积除以,得到一个新的深度图,其中每个像素的深度值都根据焦距和比例因子进行了调整。这种调整可能是为了将深度图从某种原始度量(如像素单位的倒数)转换为更物理的度量(如米或厘米),或者为了校正由于相机内参引起的某种偏差。

给出代码示例

首先,我们需要确保inv_intrinsics是一个形状为[batch_size, 3, 3]的Tensor,其中包含了逆相机内参矩阵的集合,每个矩阵的(0, 0)(1, 1)位置是焦距的倒数(即1/fx1/fy)。同时,depth应该是一个形状为[batch_size, ...]的Tensor,其中包含了每个像素的深度值。

以下是代码示例,说明了如何计算pixel_size并更新depth

import torch

# 假设 inv_intrinsics 是一个形状为 [batch_size, 3, 3] 的 Tensor
# 假设 depth 是一个形状为 [batch_size, ...] 的 Tensor
# 假设 scale_depth_by_focal_lengths_factor 是一个标量或者与 depth 形状相同的 Tensor

# 示例数据
batch_size = 4  # 假设批次大小为 4
inv_intrinsics = torch.randn(batch_size, 3, 3)  # 随机生成逆内参矩阵
depth = torch.randn(batch_size, 10, 10)  # 随机生成深度图,假设每个样本的深度图大小为 10x10
scale_depth_by_focal_lengths_factor = 0.5  # 假设的比例因子

# 计算 pixel_size
# 注意:我们只关心逆内参矩阵的对角线元素,即焦距的倒数
pixel_size = torch.sqrt(inv_intrinsics[:, 0, 0] ** 2 + inv_intrinsics[:, 1, 1] ** 2)
# 或者,如果你想使用 torch.norm 来计算两个元素的 L2 范数(几何平均值),但这里更简单的方法是直接相加然后开方
# pixel_size = torch.norm(torch.stack([inv_intrinsics[:, 0, 0], inv_intrinsics[:, 1, 1]], dim=-1), dim=-1)

# 更新 depth
depth = depth / (pixel_size.unsqueeze(1).unsqueeze(1) * scale_depth_by_focal_lengths_factor)
# 注意:我们需要使用 unsqueeze 来扩展 pixel_size 的维度,以便它可以与 depth 进行广播(broadcast)

# 此时,depth 已经根据 pixel_size 和 scale_depth_by_focal_lengths_factor 进行了更新

在这个示例中,我使用了torch.sqrt来直接计算两个焦距倒数的平方和的平方根,这是更简单且等价于使用torch.norm计算L2范数的方法。同时,我使用了unsqueeze来扩展pixel_size的维度,以便它可以与depth进行广播操作。这确保了当我们将pixel_sizedepth相除时,广播规则能够正确地将pixel_size扩展到与depth相同的形状。

1.2 我们看看BEVDepth的代码

    def _forward_single_sweep(...):
        # 提取环视图片特征
        # img_feats:[1, 1, 6, 512, 16, 44]
        img_feats = self.get_cam_feats(sweep_imgs)
        source_features = img_feats[:, 0, ...]
        
        # 提取Depth以及context
        depth_feature = self._forward_depth_net(...)
        # 预测的距离分布 depth:[6, 112, 16, 44]
        depth = depth_feature[:, :self.depth_channels].softmax(1)
        # 对应论文中的 Context Feature * Depth Distribution 操作
        img_feat_with_depth = ... # 

depth 是采用depth = depth_feature[:, :self.depth_channels].softmax(1) 均匀采样,商汤采样的的是最大深度均匀采样

采样策略:

最大深度均匀采样主要关注最大深度范围内的均匀性,而不太关心近处或中间深度层次的细节。
均匀深度分布采样则在整个深度范围内追求均匀性,确保每个深度层次都得到同等的关注。

数据分布:

最大深度均匀采样可能导致近处或中间深度层次的点或像素被过度采样,而远处深度层次的点或像素被采样不足。
均匀深度分布采样则在整个深度范围内保持相对均匀的数据分布。

适用场景:

最大深度均匀采样适用于那些主要关注远处目标或障碍物检测的应用,因为远处目标往往对任务结果有更大影响。
均匀深度分布采样适用于需要全面考虑场景深度的应用,如三维重建或增强现实。

鱼眼相机镜头对光线有折射作用,以此获得更大的可视范围,越靠近边缘区域,折射率越大,生成的图片畸变程度越大。

由于畸变,使用均匀的深度分布来生成的点云大部分位于感兴趣范围以外。
在这里插入图片描述