Android中使用CameraX如何仅采集相机画面中矩形、椭圆等指定区域

CameraX 实现仅捕获指定形状区域画面的方案
核心实现逻辑是先获取完整的相机输出帧,再结合坐标映射、遮罩、裁剪三步完成指定区域的采集,适配预览、拍照、帧分析、录像全场景:
1. 前置坐标映射
注意:做裁剪前必须先完成相机传感器坐标和屏幕坐标的映射对齐,否则会出现裁剪区域和预览显示区域错位的问题
使用CameraX提供的SurfaceOrientedMeteringPointFactory将屏幕上绘制的矩形/椭圆区域坐标,转换为相机传感器对应的比例坐标,后续所有裁剪操作都基于转换后的坐标执行。
2. 预览层仅显示指定区域
在相机预览组件PreviewView的上层叠加一个自定义遮罩View,将目标区域以外的部分做遮挡,让用户视觉上仅能看到指定区域的内容:
- 给自定义遮罩View开启硬件离屏缓冲:
setLayerType(LAYER_TYPE_HARDWARE, null) - 重写
onDraw方法实现区域镂空,核心代码示例:
override fun onDraw(canvas: Canvas) { super.onDraw(canvas) // 绘制全屏半透明遮罩 canvas.drawColor(0xAA000000.toInt()) val clearPaint = Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) isAntiAlias = true } // 镂空矩形区域 canvas.drawRect(targetRect, clearPaint) // 如需镂空椭圆/圆形,替换为如下代码即可 // canvas.drawOval(targetOval, clearPaint) }
3. 拍照/帧分析场景裁剪指定区域
如果需要实际输出裁剪后的图片、或者仅分析指定区域的内容,拿到完整的相机帧后按如下逻辑处理:
// 1. 将CameraX输出的ImageProxy转为完整Bitmap val fullBitmap = imageProxy.toBitmap() // 2. 按转换后的目标坐标裁剪对应矩形区域 val croppedRectBitmap = Bitmap.createBitmap( fullBitmap, targetRect.left.toInt(), targetRect.top.toInt(), targetRect.width().toInt(), targetRect.height().toInt() ) // 3. 如需输出椭圆形内容,给裁剪后的Bitmap加遮罩 fun getOvalBitmap(source: Bitmap): Bitmap { val outputBitmap = Bitmap.createBitmap(source.width, source.height, Bitmap.Config.ARGB_8888) val canvas = Canvas(outputBitmap) val paint = Paint().apply { isAntiAlias = true shader = BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) } canvas.drawOval(0f, 0f, source.width.toFloat(), source.height.toFloat(), paint) source.recycle() return outputBitmap }
操作完成后记得回收无用的Bitmap、关闭ImageProxy避免内存泄漏。
4. 录像场景裁剪指定区域
如果需要仅录制指定区域的内容,有两种可选方案:
- 录制时给VideoCapture的输出帧做实时遮罩渲染,再送入编码器生成视频
- 先录制完整画面,录制结束后用系统MediaEdit API对视频做指定区域裁剪
内容的提问来源于stack exchange,提问作者Khalid Aziz
相关产品推荐
相关产品推荐

