【端到端智驾基础】1.LSS-based BEV特征 Encoder
1. 端到端智驾基础之LSS目标理解 LSS 的几何投影逻辑相机投影与逆投影小孔成像模型3D 点 → 像素坐标的公式相机内参矩阵 K、外参矩阵 [R|t]核心理解 (u, v, d) ↔ (X, Y, Z) 的双向映射d 是深度LSS 三大核心步骤Lift给每个像素生成「深度分布」把 2D 特征抬升到 3D 特征Splat把 3D 特征投影到 BEV 网格上Shoot对 BEV 网格特征做池化得到最终 BEV 特征图关键概念深度分布每个像素不是单深度而是多个离散深度的概率分布体素化把 3D 空间划分为体素每个体素存储加权的特征LSS代码示例import numpy as np import matplotlib.pyplot as plt from scipy.ndimage import gaussian_filter # ---------------------- 1. 相机与BEV配置 ---------------------- fx, fy 500.0, 500.0 cx, cy 320.0, 240.0 K np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]]) bev_range 50.0 # 前后左右各50米 bev_res 0.1 # 每个栅格0.1米 grid_size int(bev_range * 2 / bev_res) num_channels 3 # 模拟3个通道的BEV特征 # 初始化多通道BEV特征图 (C, H, W) bev_features np.zeros((num_channels, grid_size, grid_size), dtypenp.float32) # ---------------------- 2. 模拟图像像素与特征 ---------------------- # 模拟从CNN backbone提取的图像特征这里简化为3通道 H_img, W_img 480, 640 # 生成一个简单的图像特征中心亮、边缘暗的3通道特征图 img_feat np.zeros((num_channels, H_img, W_img), dtypenp.float32) # np.exp(...)高斯分布离中心越近特征值越大越边缘越小。 # 三个通道写了不同中心、不同方差目的是模拟 # 通道 0图像中心区域特征强对应路面 # 通道 1图像左右两侧特征强对应两侧障碍物 # 通道 2图像中下区域特征强对应近处车辆 / 物体 for c in range(num_channels): # 每个通道有不同的模式模拟不同的语义响应 if c 0: # 通道0中心十字响应类似道路/车道线 img_feat[c, :, :] np.exp(-((np.arange(H_img)[:, None] - 240)**2 / (2*80**2) (np.arange(W_img)[None, :] - 320)**2 / (2*120**2))) elif c 1: # 通道1左右边缘响应类似障碍物轮廓 img_feat[c, :, :] np.exp(-((np.arange(H_img)[:, None] - 240)**2 / (2*150**2) (np.arange(W_img)[None, :] - 100)**2 / (2*50**2))) \ np.exp(-((np.arange(H_img)[:, None] - 240)**2 / (2*150**2) (np.arange(W_img)[None, :] - 540)**2 / (2*50**2))) else: # 通道2中下部响应类似车辆前方物体 img_feat[c, :, :] np.exp(-((np.arange(H_img)[:, None] - 350)**2 / (2*60**2) (np.arange(W_img)[None, :] - 320)**2 / (2*150**2))) # 采样像素点步长10减少计算量 pixel_step 10 pixel_coords [] pixel_feats [] for v in range(0, H_img, pixel_step): for u in range(0, W_img, pixel_step): pixel_coords.append(np.array([u, v, 1.0])) pixel_feats.append(img_feat[:, v, u]) # 取该像素的3通道特征 pixel_coords np.array(pixel_coords) pixel_feats np.array(pixel_feats) # (N, 3) # ---------------------- 3. Lift Splat 过程 ---------------------- inv_K np.linalg.inv(K) depths np.linspace(5.0, 40.0, 8) # 深度假设 depth_probs np.array([0.05, 0.1, 0.15, 0.2, 0.2, 0.15, 0.1, 0.05]) # 深度分布 # 像素和特征, 深度及分布 for uv, feat in zip(pixel_coords, pixel_feats): for d, p in zip(depths, depth_probs): # Lift: 2D像素 - 3D相机坐标 cam_pt d * (inv_K uv) bev_x cam_pt[2] # 相机Z轴是BEV的X向前 bev_y -cam_pt[0] # 相机X轴是BEV的Y向左为负向右为正 # 过滤超出BEV范围的点 if abs(bev_x) bev_range or abs(bev_y) bev_range: continue # 计算栅格索引 x_idx int((bev_x bev_range) / bev_res) y_idx int((bev_y bev_range) / bev_res) if 0 x_idx grid_size and 0 y_idx grid_size: # Splat: 把特征乘深度概率累加到对应栅格 bev_features[:, y_idx, x_idx] feat * p # 高斯平滑模拟真实Splat的软分配 sigma 3 for c in range(num_channels): bev_features[c] gaussian_filter(bev_features[c], sigmasigma) # ---------------------- 4. 可视化3个通道的BEV特征 ---------------------- fig, axes plt.subplots(1, num_channels, figsize(15, 5)) cmap jet for c in range(num_channels): ax axes[c] im ax.imshow(bev_features[c], cmapcmap, originlower) ax.set_title(fBEV Feature Channel {c}) ax.axis(off) plt.colorbar(im, axax, shrink0.8) plt.suptitle(Multi-Channel LSS BEV Features (Simulated), y1.02) plt.tight_layout() plt.show() # 也可以看所有通道的最大值合成图类似语义热力图 plt.figure(figsize(8, 6)) max_bev bev_features.max(axis0) plt.imshow(max_bev, cmapjet, originlower) plt.colorbar(labelMax Feature Value Across Channels) plt.title(BEV Feature Max Response (All Channels)) plt.axis(off) plt.show()可视化显示BEV 每个网格最终存的是什么每个栅格内不是单个数是和图像通道数一致的特征向量向量中每一维 所有投影到这里的「图像特征 × 深度概率」之和物理含义该地面位置综合所有视觉观测 深度置信后得到的聚合特征图像特征人工用高斯模拟 CNN 输出的 (C,H,W) 特征图每个像素自带一组多维特征深度 概率两个数组按下标一一配对代表像素在不同距离上的出现置信度特征 × 概率用深度置信做权重计算特征期望让可信位置特征更强是 LSS 标准 Lift 操作用来建模深度不确定性。