Android如何实现摄像头视频采集、目标检测处理后实时展示画面
CameraX实现先处理帧再渲染画面的解决方案
针对你需要先处理摄像头帧再展示到屏幕的需求,有两种成熟的实现方案:
方案1:ImageAnalysis + 自定义渲染视图
- 移除布局中的默认PreviewView,替换为自定义的
TextureView或者SurfaceView作为最终渲染载体 - CameraX绑定生命周期时,仅绑定
ImageAnalysis用例,不绑定默认Preview用例 - 给ImageAnalysis设置分析器,回调中获取每一帧的
ImageProxy对象,转换为目标检测模型需要的输入格式 - 执行目标检测推理,把检测框、类别、置信度等标注绘制到帧画面上
- 将绘制完成的帧渲染到自定义的TextureView/SurfaceView即可
注意:ImageAnalysis的回调默认运行在后台线程,渲染操作需要切换到主线程执行;如果需要优化帧率,可以把帧处理和渲染放到同一个GL线程用OpenGL做离屏渲染,减少数据拷贝开销
方案2:自定义Preview的SurfaceProvider(适合需要复用CameraX适配能力的场景)
- 保留Preview用例,但不使用PreviewView提供的SurfaceProvider,自行实现SurfaceProvider
- 自行创建一个Surface绑定到OpenGL离屏纹理,CameraX的原始帧会直接输出到这个离屏纹理
- 在GL线程中读取纹理内容做目标检测,绘制标注后再把最终纹理渲染到屏幕的视图上
- 该方案的优势是可以复用CameraX Preview的自动裁剪、分辨率适配、旋转适配等能力,不需要自己处理摄像头输出和屏幕尺寸的适配逻辑
核心代码示例
val imageAnalysis = ImageAnalysis.Builder() .setTargetResolution(Size(1280, 720)) // 适配你的模型输入分辨率 .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) // 只处理最新帧,避免帧积压 .build() imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor()) { imageProxy -> // 1. 把imageProxy转成模型需要的输入格式,比如YUV转RGB Bitmap val inputFrame = convertImageProxyToBitmap(imageProxy) // 2. 执行目标检测推理,拿到检测结果 val detectionResults = detector.detect(inputFrame) // 3. 把检测结果绘制到帧画面上 drawDetectionResult(inputFrame, detectionResults) // 4. 切换到主线程渲染到自定义TextureView runOnUiThread { val canvas = textureView.lockCanvas() canvas?.drawBitmap(inputFrame, 0f, 0f, null) textureView.unlockCanvasAndPost(canvas) } // 必须关闭imageProxy,否则后续帧不会回调 imageProxy.close() } // 绑定到页面生命周期 ProcessCameraProvider.getInstance(context).get().bindToLifecycle( lifecycleOwner, CameraSelector.DEFAULT_BACK_CAMERA, imageAnalysis )
如果你的目标检测模型需要固定分辨率的输入,直接给ImageAnalysis设置TargetResolution即可,CameraX会自动做适配,不需要自己做分辨率转换;如果要降低端到端延迟,建议把模型输入分辨率和ImageAnalysis的输出分辨率设为一致,避免额外的缩放开销。
内容的提问来源于stack exchange,提问作者deepesh mhatre
相关产品推荐
相关产品推荐

