ESC
输入关键词搜索文章标题和内容

avm_panoramic_implementation

车载360环视只是伪3D?CPU查表法 vs GPU碗状模型硬核拆解

导读

4 个鱼眼拼一张鸟瞰图,CPU 靠查表硬扛,GPU 用碗状模型渲染——但说真的,现在量产的 3D 环视全是伪 3D。CPU 方案为什么死活搞不定 3D 自由视角?GPU 碗状模型的硬伤在哪?从头拆一遍。


一、车载AVM环视系统:能干什么

AVM(Around View Monitor)要干的事就是:把装在车身四周的 4 个鱼眼摄像头拍到的画面,拼成一张从车顶往下看的完整鸟瞰图。

它解决什么问题?

驾驶员坐在车里,视野被车身遮挡,车头车尾、四个角落全是盲区。4 个鱼眼相机分别装在车头格栅、车尾牌照灯、左右后视镜下方,每个覆盖 180°+ 的视场角,四路拼接后做到 360° 无死角环视

AVM 的应用场景

场景 功能 依赖
倒车入库 鸟瞰图 + 轨迹线 方向盘转角 + 车身参数
窄路会车 左右两侧放大视图 转向灯信号触发
自动泊车 车位检测 + 泊车路径规划 AVM + 超声波雷达
透明底盘 车底历史图像拼接 轮速脉冲 + 历史帧缓存
哨兵模式 停车监控 碰撞检测 + 录像

说白了:AVM 就是给驾驶员装了一双"上帝之眼",让你从车顶往下看,车身周围的一切尽收眼底。


二、AVM系统架构总览

flowchart TB subgraph INPUT["📷 采集层"] CAMS["前视鱼眼 &nbsp;|&nbsp; 后视鱼眼 &nbsp;|&nbsp; 左视鱼眼 &nbsp;|&nbsp; 右视鱼眼&nbsp; <br/>1280×720 × 4路"] end subgraph CALIB["⚙️ 标定层"] CAL["张正友标定<br/>内参 K + 畸变 D + 外参 R|t"] end subgraph PROCESS["🔧 处理层"] direction LR CORRECT["畸变校正<br/>cv2.fisheye.undistort"] TRANSFORM["透视变换<br/>单应性矩阵 H"] BLEND["图像融合<br/>加权平均 + 渐变"] end subgraph RENDER["🎨 渲染层"] direction LR CPU["CPU 2D 渲染<br/>查表法 LUT 俯视图"] GPU["GPU 3D 渲染<br/>碗状模型 + 纹理映射"] end subgraph OUTPUT["🖥️ 输出层"] direction LR V2D["2D 鸟瞰图"] V3D["3D 自由视角"] VL["放大视图"] VT["透明底盘"] end INPUT ==> CALIB ==> PROCESS PROCESS ==> RENDER RENDER ==> OUTPUT CPU -.->|"仅此路径"| V2D GPU -.->|"全路径"| V3D GPU -.-> V2D GPU -.-> VL GPU -.-> VT style INPUT fill:#E3F2FD,stroke:#1565C0,stroke-width:2px style CALIB fill:#FFF3E0,stroke:#E65100,stroke-width:2px style PROCESS fill:#F3E5F5,stroke:#6A1B9A,stroke-width:2px style RENDER fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px style OUTPUT fill:#FFEBEE,stroke:#C62828,stroke-width:2px

整个系统里外分五层。采集层拿到 4 路 1280×720 的鱼眼图像,经过标定层拿到相机参数,处理层做畸变校正和视角变换,渲染层是分水岭——CPU 走 2D 查表,GPU 走 3D 渲染,输出层就是驾驶员看到的画面。

关键分水岭:CPU 方案只能走 2D 鸟瞰图一条路径,GPU 方案可以输出全部四种视图(2D 鸟瞰、3D 自由视角、放大视图、透明底盘)。


三、CPU版:2D俯视图是怎么做出来的

3.1 思路

把4个鱼眼相机拍到的、各自朝向不同方向的画面,统一"拍到一个水平地面上",然后拼成一张正上方看的鸟瞰图。

听起来简单,做起来全是细节。

第一步:去畸变

鱼眼镜头的畸变是"有意为之"——为了用一颗镜头覆盖180°+的视场,画面边缘必然严重弯曲。去畸变就是把弯曲的线条拉直,把扭曲的像素归位到针孔相机模型的投影位置。

第二步:透视变换

去畸变后的图像还是"从相机角度看的",需要变成"从正上方看的"。本质是求解一个单应性矩阵 H(3×3的变换矩阵),把路面上的点映射到俯视图的对应位置。

第三步:四路拼接

四路画面各自被变换到俯视图后,会有重叠区域。需要对重叠区域做融合(加权平均或线性混合),让拼接缝消失。

3.2 查表法(LUT):CPU方案的核心

如果每帧都实时计算透视变换——每个像素都要乘 3×3 矩阵、做一次除法、再插值——CPU 根本扛不住。

查表法的思路是:

标定完成后,相机和地面的位置关系就固定了。俯视图上每个像素点对应原始鱼眼图像的哪个坐标,是永远不变的。既然如此,标定完就把这个映射关系算好,存成一张表,以后每帧直接查表就行了。

说白了就是一张 "离线映射表"

俯视图坐标 (u, v) → 查表 → 原始图像坐标 (x, y) → 取像素 → 填到俯视图

怎么做

  1. 标定阶段,根据相机的内参、外参、畸变系数,计算出俯视图上每个像素 (u, v) 对应的世界坐标 (X, Y, 0)
  2. 把世界坐标反投影到相机坐标系,再投影到鱼眼图像坐标 (x, y)
  3. 同时算好每个像素的融合权重(相邻相机重叠区域做渐变)
  4. (x, y, weight) 三件套存成一张查找表
  5. 运行时,遍历俯视图的每个像素,查表取坐标,从原始图像取像素值,乘以权重,填到输出画面

查表法为什么能跑在 CPU 上

  • 表算好了就不动了,运行时就是"读表 + 取像素 + 乘法",没有矩阵运算,CPU 轻松扛住
  • 可以改成整型运算(定点数),不用浮点
  • 可以配合 DMA 批量搬数据,减少 CPU 参与

3.3 图像融合:让拼接缝消失

四路画面拼在一起,重叠区域如果不处理,会看到明显的拼接缝。

为什么会有拼接缝?

  • 四路相机曝光不同(车头对着太阳、车尾在阴影里,亮度差很多)
  • 白平衡不一致(即使同一型号的相机,出厂微调也有差异)
  • 拼接处几何对不齐(标定误差的累积)

融合方法

重叠区域的像素值 = 左边相机的像素 × weight_left + 右边相机的像素 × weight_right

weight 在重叠区域从 1 渐变到 0,实现平滑过渡。这个权重也提前算好存在查表里。

本节要点:CPU 查表法的核心是用空间换时间——标定时把映射关系全算好,运行时只查表不计算。三个步骤:去畸变 → 透视变换 → 四路融合。缺点是只能输出固定视角的俯视图,换视角就得重新生成表。

3.4 CPU版完整流程

flowchart TB S1["📥 输入 4路鱼眼图像<br/>1280×720 ×4"] S1 --> S2["⚙️ 加载标定参数<br/>内参 K + 畸变系数 D"] S2 --> S3["📋 加载查找表 LUT<br/>坐标映射 + 融合权重"] S3 --> S4["🔍 逐像素查表<br/>俯视图坐标 → 原始图像坐标"] S4 --> S5["🎯 双线性插值<br/>亚像素精度采样"] S5 --> S6["🖌️ 重叠区域加权融合<br/>weight_left + weight_right = 1"] S6 --> S7["📐 输出 2D 鸟瞰图<br/>880×1080"] S7 --> S8["🚗 叠加动态轨迹线<br/>方向盘转角 → 轮胎轨迹"] S8 --> S9["🖥️ 显示到屏幕"] style S1 fill:#E3F2FD,stroke:#1565C0,stroke-width:2px style S2 fill:#FFF3E0,stroke:#E65100,stroke-width:2px style S3 fill:#FFF3E0,stroke:#E65100,stroke-width:2px style S4 fill:#FFF8E1,stroke:#F9A825,stroke-width:2px style S5 fill:#F3E5F5,stroke:#6A1B9A,stroke-width:2px style S6 fill:#F3E5F5,stroke:#6A1B9A,stroke-width:2px style S7 fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px style S8 fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px style S9 fill:#FFEBEE,stroke:#C62828,stroke-width:2px

四、GPU版:3D环视是怎么做出来的

4.1 为什么需要3D

2D俯视图有个要命的问题:只有俯视一个视角

倒车入库时俯视图很好用,但你想看车头前方3米的情况、想看右前轮旁边的马路牙子——俯视图帮不了你。2D方案只能靠"切换摄像头"来模拟(比如放大前视图、放大左右视图),但这些画面还是"从相机角度看的",不是"从驾驶员视角看的"。

3D环视的好处就是:你想从哪个角度看,就从哪个角度看

4.2 思路:3D碗状模型 + 纹理映射

3D环视不是把图像"拍平"到地面上,而是把图像贴到一个3D曲面模型上,然后用虚拟相机在这个3D场景里漫游。

flowchart TB subgraph OFFLINE["🏗️ 离线建模阶段"] direction LR M1["3D 碗状曲面建模<br/>3ds Max / 程序化生成"] M1 --> M2["导出网格顶点数据<br/>position + normal + texcoord"] M2 --> M3["保存模型文件<br/>.obj / .ply / 自定义格式"] end subgraph INIT["🚀 系统初始化阶段"] direction LR I1["加载 3D 碗状模型网格"] I1 --> I2["初始化 OpenGL ES 环境<br/>EGL 上下文 + 着色器 + FBO"] I2 --> I3["建立纹理坐标映射<br/>网格顶点 → 鱼眼图像坐标"] end subgraph RUNTIME["⚡ 每帧运行时"] direction LR R1["4路鱼眼图像上传 GPU<br/>glTexImage2D → 4个纹理单元"] R1 --> R2["虚拟相机位置更新<br/>触摸 / 档位 / 转向灯触发"] R2 --> R3["计算 MVP 矩阵<br/>Model × View × Projection"] R3 --> R4["GPU 着色器渲染<br/>顶点着色器 + 片段着色器"] R4 --> R5["Alpha 混合融合<br/>color0×α + color1×(1-α)"] R5 --> R6["输出 3D 环视画面<br/>FBO → 屏幕"] end OFFLINE ==> INIT ==> RUNTIME style OFFLINE fill:#E3F2FD,stroke:#1565C0,stroke-width:2px style INIT fill:#FFF3E0,stroke:#E65100,stroke-width:2px style RUNTIME fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px

碗状模型是什么?

想象一个碗扣在地上,碗的内壁就是投影面。车身在地面中心,四路相机的画面被纹理映射到碗的内壁上——车头前方贴碗的前壁,车尾后方贴碗的后壁,左右两侧贴碗的左右壁。

为什么用碗状而不是平面?

  • 平面投影:近处物体正常,远处物体被拉伸成面条(因为平面假设地面是无限远的水平面,但实际相机拍到的远景包含了天空和远处建筑物)
  • 碗状投影:碗壁向上弯曲,远景贴在碗壁上,视角更自然,边缘不拉伸

除了碗状,还有哪些变种?

五平面投影(地面 + 四面斜坡)、半椭球投影。说穿了都是折中——在"地面平坦"和"远景不拉伸"之间找平衡,没有完美的解。

一句话:碗状模型 = 3D 曲面网格 + 纹理映射 + 虚拟相机。GPU 三阶段:离线建模 → 系统初始化 → 每帧渲染。

4.3 GPU具体怎么干(以OpenGL ES为例)

下面一步步拆开看 GPU 是怎么干的。

1. 初始化 OpenGL ES 环境

用 EGL 创建离屏渲染上下文(不显示在屏幕上,渲染到 FBO)。车载 SoC 通常支持 OpenGL ES 2.0/3.0

技能点:
- eglCreateContext 创建 GL 上下文
- eglCreatePbufferSurface 创建离屏表面
- 加载顶点着色器和片段着色器(从文件或内嵌字符串)

2. 加载 3D 碗状模型

模型格式:顶点数组 (x, y, z) + 纹理坐标 (u, v) + 法线 (nx, ny, nz) + Alpha 值(用于融合)。

结构体大约是:

顶点属性交错存储:
position(3 float) + texCoord0(2 float) + texCoord1(2 float) + alpha(4 float)

两个纹理坐标对应两个相邻相机的纹理采样(用于重叠区域的 Alpha 混合)。

3. 上传 4 路鱼眼图像为纹理

每帧把 4 路鱼眼图像通过 glTexImage2D 上传到 GPU,绑定到 4 个纹理单元(GL_TEXTURE0 ~ GL_TEXTURE3)。

4. 顶点着色器:坐标变换

// 顶点着色器就是干这个的
gl_Position = matMVP * vec4(a_position, 1.0);
v_texCoord0 = a_texCoord0;  // 相机A的纹理坐标
v_texCoord1 = a_texCoord1;  // 相机B的纹理坐标
v_alpha = max(min(a_alpha, 1.0), 0.0);  // 融合权重

matMVP = Projection × View × Model。Model矩阵把碗状模型放到世界坐标系,View矩阵是虚拟相机的位置和朝向,Projection矩阵是透视投影。

5. 片段着色器:纹理采样 + Alpha融合

// 片段着色器:两张纹理混合
color0 = texture(sTexture0, v_texCoord0);  // 从相机A采样
color1 = texture(sTexture1, v_texCoord1);  // 从相机B采样
FragColor = color0 * v_alpha + color1 * (1.0 - v_alpha);  // Alpha混合

6. 虚拟相机控制

虚拟相机就是 View 矩阵的计算。控制虚拟相机的位置(eye position)和朝向(look-at point),就能切换视角:

视角 虚拟相机位置 朝向
鸟瞰(Top View) 车顶正上方,高度约 5m 垂直向下
3D 前视 车顶前上方,偏右 前方偏下
3D 后视 车顶后上方 后方偏下
3D 左前 车顶左前上方 左前轮方向
360° 旋转 围绕车顶圆周运动 始终指向车身中心

7. 车身模型渲染

在碗状场景之上,还要渲染一个 3D 车身模型(包括透明底盘效果)。车身模型和碗状模型共用同一个 MVP 矩阵,但材质不同。透明底盘需要额外处理——把前几帧已经渲染到地面的图像缓存起来,作为车底纹理。

8. 输出到屏幕

渲染完成后,从 FBO 读回像素数据,走 DRM/KMS(Linux)或 FrameBuffer 直接显示到屏幕。

GPU 渲染管线总结:初始化 OpenGL ES → 加载碗状模型 → 上传 4 路纹理 → 顶点着色器做 MVP 变换 → 片段着色器做纹理采样 + Alpha 混合 → 虚拟相机随意切换视角 → FBO 输出到屏幕。核心是 MVP 矩阵变换 + 纹理映射 + Alpha 混合,全部在 GPU 上并行完成。

4.4 GPU版的优缺点

优点

优点 说明
自由视角 虚拟相机可以在3D场景中任意移动,想看哪个角度就看哪个角度
画面质量高 3D投影消除了2D方案的边缘拉伸问题,远景也清晰
GPU并行加速 纹理采样、矩阵运算、Alpha混合全在GPU上并行完成,CPU几乎不参与
支持特效 透明底盘、雷达叠加、车模动画都能在GPU上自然实现
可扩展 增加视角只改View矩阵,不需要改渲染管线

缺点

缺点 说明
需要GPU 低端车机芯片上没有GPU或GPU太弱,3D渲染跑不起来
开发复杂 3D建模 + OpenGL着色器 + 纹理映射,比CPU查表复杂得多
调试困难 CPU查表法出问题,打印几个像素值就能定位;GPU渲染出问题,得用RenderDoc之类的工具抓帧分析
功耗更高 GPU一直开着比CPU查表耗电,对纯电车的续航有影响
纹理精度损失 鱼眼图像边缘分辨率低,贴到碗壁上会被放大,远处不够清晰
路面不平时拼缝明显 标定假设地面是完美平面,实际路面有坡度、坑洼、减速带,拼接处会出现错位和重影
碗状模型远近畸变 碗状模型是固定曲面,近处物体(< 0.5m)和远处物体(> 5m)投影到碗壁上会严重变形,不是真实光学投影
本质是伪3D 碗状模型只是把2D纹理贴到3D曲面上,没有真实的深度信息,不是真正的3D重建

4.5 GPU 3D环视的本质缺陷——伪3D的真相

GPU 3D环视看着炫,但有三个绕不过去的硬伤:

1. 路面不平——拼缝原形毕露

flowchart LR subgraph 理想["✅ 标定假设"] I1["地面是完美水平面<br/>Z = 0 处处成立"] I2["单应性矩阵 H 成立<br/>所有路面点精确映射"] end subgraph 现实["❌ 实际路面"] R1["坡度 / 坑洼 / 减速带<br/>Z ≠ 0"] R2["单应性假设失效<br/>拼接处出现错位和重影"] R3["四路相机交界处<br/>最明显"] end subgraph 后果["⚠️ 驾驶员看到"] C1["地面标线断开<br/>看起来像两条线"] C2["障碍物形状扭曲<br/>影响距离判断"] end 理想 -.->|"标定在平坦车间完成"| 现实 现实 --> 后果 style 理想 fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px style 现实 fill:#FFEBEE,stroke:#C62828,stroke-width:2px style 后果 fill:#FFF3E0,stroke:#E65100,stroke-width:2px

AVM 标定是在平坦的标定间里完成的,假设地面是完美的 Z=0 平面。但实际驾驶中,路面有坡度、有坑洼、有减速带。一旦地面不是平的,单应性矩阵 H 的假设就失效了——四个相机交界处的路面点投影到俯视图上,会出现在不同的位置,拼缝就露出来了。

路面越不平,拼缝越明显。这也是为什么在越野、工地、烂路场景下,AVM 的环视画面看着"怪怪的"——地面标线在拼接处断开了,障碍物形状扭曲了。

2. 碗状模型——太近太远都畸变

碗状模型是一个固定曲面,不是根据实际场景动态生成的。问题出在两个极端:

  • 太近(< 0.5m):碗底中心区域曲率变化剧烈,近处物体贴到碗底中心,投影关系在中心小范围内剧烈变化,物体会被"压扁"或"拉长"
  • 太远(> 5m):碗壁向上弯曲,远处物体贴到碗壁上,投影关系变成曲线投影。碗壁的曲率是固定的,不会根据实际深度调整——一个 3 米外的路沿和一个 10 米外的建筑物,在碗壁上被"一视同仁",导致近处物体被拉伸、远处物体被压缩

这矛盾无解:你想要一个固定的碗同时适配 0.3m 和 30m 的场景,不可能。任何固定曲面模型都是折中。

3. 本质是伪3D——没有深度信息

flowchart TB subgraph 伪3D["🔶 伪3D(当前方案)"] P1["4路鱼眼图像"] P2["纹理映射到碗状曲面"] P3["虚拟相机透视投影"] P4["⚠️ 只是'看起来像3D'<br/>其实只是2D纹理被贴到3D曲面上"] P5["没有真实深度<br/>无法判断物体距离"] end subgraph 真3D["🔷 真3D(理想方案)"] T1["4路鱼眼图像"] T2["多目立体匹配<br/>计算每个像素深度"] T3["生成3D点云<br/>+ 三角网格重建"] T4["✅ 真正的3D场景重建<br/>每个顶点有真实深度值"] T5["可以测量距离<br/>可以做碰撞检测"] end P1 --> P2 --> P3 --> P4 --> P5 T1 --> T2 --> T3 --> T4 --> T5 style 伪3D fill:#FFF3E0,stroke:#E65100,stroke-width:2px style 真3D fill:#E3F2FD,stroke:#1565C0,stroke-width:2px style P4 fill:#FFEBEE,stroke:#C62828,stroke-width:2px style T4 fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px

现在市面上的"3D 环视"都是伪3D。说白了就是:把4张2D鱼眼图像当作纹理,贴到一个3D碗状模型上,然后渲染。碗状模型的顶点坐标是固定的,不管车前方是平地还是墙壁,碗状模型都不变——它只是"看起来"像3D,实际上没有深度信息。

真正的3D需要多目立体匹配:利用4路相机之间的视差,计算每个像素的深度值,生成3D点云,然后做三角网格重建。这才是真正的3D场景重建。但多目匹配的计算量巨大,在车机芯片上实时跑还很难。

伪3D的后果

  • 不能判断物体的真实距离(碗状模型上的顶点坐标是固定的3D位置,不是根据实际场景重建的,曲面上的"距离"和真实世界的距离对不上)
  • 不能做碰撞检测(你不知道障碍物离车身有多远)
  • 障碍物在碗壁上的投影位置和实际位置不一致(尤其是高处的物体,比如路灯杆、树枝)

总结:GPU 3D环视比CPU 2D方案强很多,但它不是"真3D"。它只是把2D纹理贴到3D曲面上,让你感觉像在看3D。路面不平、远近畸变、缺乏深度——这三个问题,要等真正的多目深度估计方案成熟后才能解决。

本节要点:GPU 3D 环视 = 碗状模型 + 纹理映射 + 虚拟相机。优点是自由视角、画面质量高、GPU 并行加速。缺点是伪 3D(无深度)、路面不平拼缝裂开、远近畸变、功耗高。记住:现在的"3D 环视"只是纹理贴曲面,不是真正的 3D 重建。


五、CPU 2D方案为什么搞不定3D

CPU查表法能跑2D俯视图,但3D自由视角是它永远跨不过去的坎:

1. 查表法天生是"固定视角"

查表法把"俯视图像素 → 鱼眼图像坐标"的映射固定死了。它的输出永远是俯视图,你想看3D左前方向?没办法,那张表只定义了俯视的映射关系。换一个视角就要重新生成一张表,而表的大小和视角数量成正比——8个视角就是8张表,内存爆炸。

2. 透视投影算不动

3D视角的本质是透视投影——近处的物体大、远处的物体小。CPU查表法用的是单应性变换(平面到平面的映射),无法表达透视效果。要模拟透视,每个像素的映射关系都不同,而且随着虚拟相机移动而实时变化,CPU根本算不过来。

3. 遮挡关系处理不了

3D场景中,碗壁上的一个面可能挡住另一个面。GPU可以用深度测试(Z-Buffer)自动处理遮挡,CPU方案要自己实现遮挡判断——在720p分辨率下,就是近百万次的深度比较,实时性没戏。

4. 纹理采样精度不够

查表法通常用双线性插值从鱼眼图像取像素。但3D环视需要多次纹理采样(比如鱼眼图像→3D曲面→虚拟相机视角,经过两次投影变换),双线性插值会产生明显的锯齿和模糊。GPU的mipmap和anisotropic filtering能解决这个问题,CPU没有这些硬件特性。

5. 融合计算量指数增长

2D俯视图只需要在重叠区域做一次融合(4个重叠区域)。3D环视中,每个三角面片都可能跨越两个相机的边界,需要逐面片做Alpha混合。CPU遍历每个面片的速度远不如GPU的并行着色器。

flowchart TB subgraph CPU["🔴 CPU 2D 查表方案"] direction TB C1["🗺️ 固定映射表<br/>俯视图 (u,v) → 鱼眼 (x,y)"] C2["📐 仅支持俯视<br/>视角不可变"] C3["📏 单应性变换<br/>无透视投影"] C4["🚫 无深度信息<br/>无法处理遮挡"] C5["🔢 双线性插值<br/>精度有限"] C6["🟨 4个融合区域<br/>固定重叠区"] C_FAIL["⛔ 无法实现<br/>3D 自由视角"] end subgraph GPU["🟢 GPU 3D 渲染方案"] direction TB G1["🎯 MVP 矩阵实时变换<br/>视角自由切换"] G2["🔭 任意视角漫游<br/>8方向 + 360°旋转"] G3["🔺 透视投影<br/>近大远小自然"] G4["📊 Z-Buffer 深度测试<br/>硬件自动遮挡"] G5["🎨 硬件纹理采样<br/>Mipmap + 各向异性过滤"] G6["🟩 逐面片 Alpha 混合<br/>GPU 着色器并行"] G_OK["✅ 支持任意视角<br/>3D 自由漫游"] end C1 --> C2 --> C3 --> C4 --> C5 --> C6 --> C_FAIL G1 --> G2 --> G3 --> G4 --> G5 --> G6 --> G_OK style CPU fill:#FFEBEE,stroke:#C62828,stroke-width:2px style GPU fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px style C_FAIL fill:#B71C1C,color:#FFFFFF,stroke:#B71C1C,stroke-width:2px style G_OK fill:#1B5E20,color:#FFFFFF,stroke:#1B5E20,stroke-width:2px

本节要点:CPU 搞不定 3D 的根因——查表法是固定映射,换视角就得重建表;单应性变换表达不了透视投影;没有 Z-Buffer 做遮挡判断;没有硬件纹理采样;融合计算量指数增长。CPU 方案对 3D 自由视角"没戏"


六、车载环视的发展方向

1. 从4路到更多路

4路鱼眼是现在的主流,但已经有车厂在试6路甚至8路方案。侧前方和侧后方各加一个相机,减少死角,提高拼接精度。更多相机意味着更多的重叠区域,标定和融合的复杂度翻倍。

2. 从"看"到"理解"

现在的AVM只是"把画面拼出来给人看",下一步是"让系统理解画面里有什么"。用深度学习做语义分割,识别出车位线、路沿、障碍物、行人,把信息叠加到环视画面上。GPU不仅要有渲染能力,还得有推理能力(NPU/GPU Compute)。

3. 和传感器融合

环视只是视觉,但自动驾驶需要多传感器融合。AVM + 超声波雷达(短距)+ 毫米波雷达(中距)+ 激光雷达(可选)= 完整的感知系统。3D环视的碗状模型可以作为传感器融合的统一坐标系——所有传感器数据投影到同一个3D场景中。

4. 自适应3D投影

现在的3D环视用的是固定碗状模型,不能根据场景变化。前方有障碍物时,应该自动把虚拟相机抬高,让你看到障碍物后面有什么;高速行驶时,应该把视角拉远,扩大视野范围。用光流分析或语义信息,自适应调整投影模型。

5. 纯视觉深度估计

现在的3D环视只是"透视投影",不是真正的3D重建——它没有深度信息。如果能从4路图像中估计出每个像素的深度(类似双目立体匹配,但用4路多目),就可以实现真正的3D场景重建,不再依赖固定碗状模型。

6. 车机芯片升级

车载GPU从OpenGL ES 2.0升级到Vulkan/OpenGL ES 3.2,支持更复杂的着色器,可以做出更好的光照效果、阴影、反射。高通车机芯片(如SA8295)的GPU已经接近PC级,3D环视的画质还有很大提升空间。

发展关键词:更多路 → 语义理解 → 传感器融合 → 自适应投影 → 纯视觉深度估计 → 芯片升级。终极目标是:从"给人看"进化到"让系统理解",从"伪3D"进化到"真3D重建"。


七、总结

维度 CPU 2D查表方案 GPU 3D渲染方案
核心原理 离线查表:俯视图→鱼眼图像坐标映射 3D碗状模型 + OpenGL纹理映射 + 虚拟相机
视角 仅俯视 任意视角漫游
画面质量 边缘拉伸,远景模糊 远近均匀,边缘自然
算力 CPU 密集,逐像素遍历 GPU 并行,着色器一次处理全屏
开发难度 低(查表逻辑简单) 高(3D建模+着色器+纹理管线)
功耗 中高
适用平台 低端车机(无GPU) 中高端车机(有GPU)
代表场景 早期车载环视、后装市场 前装量产、自动泊车
路面适应性 同GPU方案,也怕不平 路面不平时拼缝明显
3D真实性 无3D 伪3D(纹理贴曲面,无深度)

记住这几点

  1. AVM 就是拼 4 路鱼眼图像,给你 360° 上帝视角
  2. CPU 2D 方案的本质是查表法——标定阶段算好映射关系,运行时只查表,不计算
  3. 查表法简单直接,但只能输出固定视角的俯视图,没法做 3D 自由视角
  4. GPU 3D 方案用碗状模型 + 纹理映射,虚拟相机可以在 3D 场景里随便转
  5. 3D 环视的 GPU 实现涉及:OpenGL 初始化 → 模型加载 → 纹理上传 → MVP 矩阵 → 着色器渲染 → Alpha 混合 → FBO 输出
  6. CPU 方案搞不定 3D 的根因:查表法是固定映射、单应性变换无透视、无深度、无硬件纹理采样、融合计算量指数增长
  7. GPU 3D 方案的三个硬伤:路面不平拼缝裂开、碗状模型远近畸变、本质是伪 3D 没有深度
  8. 发展方向:更多相机 → 语义理解 → 传感器融合 → 自适应投影 → 纯视觉深度估计 → 芯片升级

AVM 从 2D 到 3D 的进化,说白了是从"算好了给你看"到"你想怎么看就怎么看"。GPU 让这件事变成了可能,车机芯片升级让 3D 环视从高端车走向普及。但别忘了,现在的"3D 环视"只是伪 3D——把纹理贴在碗上,不是真正的 3D 重建。真正的 3D,要等多目深度估计成熟之后。

返回首页