本文档主要介绍利用某导航SDK开发AR导航的流程(获取并传递图片)和注意事项,基础导航、图像的检测、AR融合算法皆由SDK提供。
车载AR导航介绍
车载AR导航机制一般为:首先利用摄像头将前方道路的真实场景实时捕捉下来,再结合汽车当前定位及传感器(陀螺仪、惯导)数据、地图导航信息以及场景AI识别,进行融合计算,然后生成虚拟的导航指引模型,并叠加到真实道路上,从而创建出更贴近驾驶者真实视野的导航画面。
车载AR导航系统需要实现的能力:
- 车道级导航能力。基础导航能力。
- 图像获取、检测与识别能力。
- AR融合算法能力。
前置条件
- 基础导航。AR导航是基于基础导航的,基础导航的基本功能必须是完善的、没有问题的。
- 基于DR的定位模式。DR定位模式可以提高AR导航的精度,使得AR引导提示得更加精准。
- 摄像头。支持YUV格式帧流的摄像头(基本都支持),预览帧率必须不小于20fps(这个要根据具体SDK的AR服务要求来,我所使用的SDK中请求图片的帧率约为20fps)。
- 传感器。三轴陀螺仪、三轴加速度,其丢帧率和稳定性要符合SDK提供方的要求。
- 车身信息。车速信息、倒车信号、方向盘信息、车灯信息、雨刮器信息等。
其他具体要求看SDK提供方的文档。
整体架构
架构图如下
说明:
- HMI通过摄像头获取路况预览帧流(Camera数据)、通过传感器获取加速度和陀螺仪信息(IMU数据)、通过车机接口获取车辆相关信息如方向盘等(Viechle数据)等,传给AutoSDK中ARService进行处理。
- HMI通过卫星天线、传感器等获取定位、加速度、陀螺仪等信息传给AutoSDK中定位服务进行处理。
- 通过以上两步,SDK将AR图像替换底图并传递给HMI回调信息。
开发流程
主要流程为:查看摄像头参数、获取并缓存图片、传递图片、传递各种传感器和车身信息等。
本次开发中使用了罗技C270i USB摄像头,车机底层做了适配,因此可以直接用Android原生的Camera2相关接口开发。
查看摄像头参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
int[] formats = map.getOutputFormats();
Size[] sizes = map.getOutputSizes(ImageFormat.YUV_420_888);
Range<Integer>[] fpsRanges = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
|
获取预览帧流
利用Camera2API获取摄像头预览帧流。
由于AR服务是通过回调请求图片,因此拍摄后的图片需要进行缓存,待AR回调时传给AR服务。可使用一个长度为2的队列进行缓存,要保证缓存数据为最新。队列长度不能太大,否则会造成较大的延时,也不能太小,否则会丢帧。
部分关键代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
|
mImageReader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 2); mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, new Range<>(30, 30));
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
Log.e(TAG, "ImageSaver-run: " + "format=" + mImage.getFormat() + ", width=" + mImage.getWidth() + ", height=" + mImage.getHeight() + ", plans count=" + mImage.getPlanes().length + ", timestamp=" + mImage.getTimestamp()); for (int i = 0; i < mImage.getPlanes().length; i ++) { Log.e(TAG, "ImageSaver-run: " + ", plan-" + i + ", bufferSize=" + mImage.getPlanes()[i].getBuffer().remaining() + ", pixelStride" + mImage.getPlanes()[i].getPixelStride() + ", rowStride" + mImage.getPlanes()[i].getRowStride() ); }
private ImageInfo parseToImageInfo(Image image) { ImageInfo info = new ImageInfo(); info.type = IMAGE_TYPE.IMAGE_TYPE_YUV_420_888; info.width = image.getWidth(); info.height = image.getHeight(); info.timeStamp = image.getTimestamp(); info.data = new ArrayList<>(); for (int i = 0; i < image.getPlanes().length; i++) { Image.Plane plane = image.getPlanes()[i]; ByteBuffer buffer = plane.getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); ImageChannel ic = new ImageChannel(bytes, bytes.length, plane.getRowStride(), plane.getPixelStride()); info.data.add(ic); } return info; }
|
根据SDK文档设置AR服务
- 获取AR服务
- 设置资源代理,主要是AR引导图片、配置文件等
- 设置AR服务需要的摄像头参数
- 设置AR引擎需要在view中显示的大小
- 在AR服务回调里传入图片
- 设置IMU信息。导航过程中实时更新。
- 设置车辆状态信息:雨刮、档位、转向灯、方向盘。导航过程中实时更新。
- 等等
具体代码就不贴了,不同SDK不一样,根据SDk文档来即可。