第1章 车载摄像头与视觉:倒车影像、360环视、DMS驾驶员监控、AR导航
各位同学,咱们今天聊点实在的。车载摄像头,说白了就是车的“眼睛”。我最早接触这块是在2018年,当时帮一家Tier1做倒车影像的HAL层适配。嗯,那会儿Android Automotive还没现在这么成熟,踩了不少坑。今天我把这些经验掰开揉碎,跟你好好讲讲。
1.1 车载摄像头的硬件基础
先说说硬件。车载摄像头和手机摄像头,完全是两码事。手机摄像头追求的是“拍得好看”,车载摄像头追求的是“看得准、反应快”。
常见的车载摄像头有这几种:
- 后视摄像头:用于倒车影像,一般装在牌照灯附近
- 环视摄像头:4-6个广角摄像头,覆盖车身四周
- DMS摄像头:装在方向盘或A柱上,盯着驾驶员的脸
- 前视摄像头:用于ADAS和AR导航,装在挡风玻璃后面
我建议你记住一个关键参数:帧率。倒车影像至少需要30fps,DMS最好做到60fps。为什么?你想想看,如果驾驶员转头时画面卡顿,那可就危险了。
核心要点:车载摄像头通常使用GMSL(Gigabit Multimedia Serial Link)或FPD-Link传输,不是USB。这意味着你的Android系统需要通过串行器/解串器(SerDes)芯片来对接。
1.2 倒车影像:最基础也最容易踩坑
倒车影像,每个车都有。但在Android Automotive上实现,有几个坑你得注意。
首先,倒车影像的显示优先级是最高的。不管用户在干嘛——导航、听歌、看视频——只要挂入R挡,必须立刻切到倒车画面。这个逻辑在Android里叫“优先级窗口”,我建议你用WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY配合系统级权限来实现。
其次,延迟问题。从挂R挡到画面显示,行业标准是小于200ms。我在项目中遇到过,有些方案商给的Camera HAL层初始化就要300ms,这肯定不行。解决办法是:保持Camera HAL常驻,不要每次挂R挡才初始化。
我的经验:在Android Automotive中,倒车影像的SurfaceView要设置setZOrderOnTop(true),否则会被其他窗口挡住。我曾经因为这个bug排查了两天,最后发现是Z-order的问题。
代码示例,一个简单的倒车影像SurfaceView:
public class RearViewSurfaceView extends SurfaceView {
public RearViewSurfaceView(Context context) {
super(context);
setZOrderOnTop(true);
getHolder().setFormat(PixelFormat.TRANSPARENT);
}
public void startPreview() {
// 这里调用Camera HAL的startPreview
// 注意:不要在这里做耗时操作
}
}
1.3 360环视:拼接与畸变校正
360环视,说白了就是把4-6个摄像头的画面拼成一个鸟瞰图。这里有两个技术难点:畸变校正和图像拼接。
广角摄像头拍出来的画面是“鱼眼”效果,必须做畸变校正。校正算法一般用OpenCV的cv::fisheye::undistortImage()。但注意,这个函数在ARM架构上跑得很慢。我建议你用GPU加速,或者用高通、联发科提供的硬件ISP模块。
图像拼接就更讲究了。每个摄像头之间有重叠区域,需要做特征点匹配和融合。我记得有一次,客户反映环视画面在拼接处有“鬼影”,后来发现是曝光参数不一致导致的。解决办法是:所有环视摄像头使用相同的曝光时间和增益。
警告:360环视的标定非常关键。如果摄像头安装角度有偏差,拼接出来的画面会变形。建议在产线做自动化标定,不要依赖人工。
下面这张图展示了360环视系统的核心流程:
1.4 DMS驾驶员监控:人脸与视线追踪
DMS(Driver Monitoring System)这两年越来越火。欧洲NCAP已经要求2024年起新车必须配备DMS。国内虽然还没强制,但很多车企已经在预研了。
DMS的核心技术包括:
- 人脸检测:用MTCNN或RetinaFace,检测驾驶员的脸部位置
- 关键点定位:68点或106点人脸关键点,用于判断头部姿态
- 视线估计:通过眼球中心和瞳孔位置,估算视线方向
- 疲劳检测:基于PERCLOS(眼睛闭合比例)算法
我在项目中遇到过一个问题:DMS摄像头在逆光环境下,人脸检测率会大幅下降。后来我们加了HDR(高动态范围)模式,才解决了这个问题。嗯,这里要注意,DMS摄像头必须支持WDR(宽动态范围),否则白天逆光、晚上暗光都搞不定。
性能要求:DMS算法必须在30ms内完成一帧处理,否则会有延迟感。建议使用NPU(神经网络处理器)加速,不要纯用CPU。
一个简单的DMS检测流程伪代码:
// 伪代码:DMS检测流程
while (camera.isStreaming()) {
Frame frame = camera.capture();
Rect faceRect = faceDetector.detect(frame); // 人脸检测
if (faceRect != null) {
Landmark[] landmarks = landmarkDetector.detect(frame, faceRect); // 关键点
float headPose = estimateHeadPose(landmarks); // 头部姿态
float gaze = estimateGaze(landmarks); // 视线估计
if (headPose > THRESHOLD || gaze < MIN_GAZE) {
triggerAlert("驾驶员分心!");
}
}
}
1.5 AR导航:虚拟与现实叠加
AR导航,说白了就是在真实路况画面上叠加导航指示。比如在前视摄像头的画面上,画一个箭头告诉你“前方200米右转”。
AR导航的技术栈包括:
- 前视摄像头:提供实时路况画面
- IMU/GNSS:提供车辆位置和姿态
- SLAM或VIO:视觉惯性里程计,用于精确跟踪
- 渲染引擎:OpenGL ES或Vulkan,用于叠加3D箭头
我建议你使用Google的ARCore或者华为的HMS AR Engine来做AR导航。它们已经封装好了VIO和平面检测,你只需要关心导航逻辑。
避坑指南:我曾经在AR导航项目里直接用GPS坐标来定位箭头,结果发现GPS有5-10米的误差,箭头经常飘到马路对面。后来改用视觉+IMU融合定位,精度才达到亚米级。
AR导航的渲染流程大致如下:
// 伪代码:AR导航渲染
void onFrame(SurfaceTexture cameraTexture) {
// 1. 获取当前位姿
Pose pose = vio.getCurrentPose();
// 2. 计算导航点相对于车辆的位置
Vector3 navPoint = navigation.getNextTurnPoint();
Vector3 localPoint = pose.transformToLocal(navPoint);
// 3. 在画面上叠加3D箭头
renderer.beginFrame();
renderer.drawCameraBackground(cameraTexture);
renderer.drawArrow(localPoint, Color.RED);
renderer.endFrame();
}
1.6 本章小结
车载摄像头这块,技术点其实不少。但核心就三件事:低延迟、高可靠性、精准标定。不管你是做倒车影像、360环视、DMS还是AR导航,这三个点都是绕不开的。
我个人习惯是,拿到一个新项目,先搞清楚摄像头硬件接口(GMSL还是FPD-Link),再确认ISP能力(是否支持HDR、WDR),最后才写代码。顺序搞反了,后面全是坑。
好了,这一章就到这里。下一章咱们聊聊音频系统——车载音频和手机音频完全是两码事,到时候我给你讲讲怎么在Android Automotive上做多音区控制。
公众号:蓝海资料掘金营,微信deep3321