You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Android Jetpack CameraX中实现感兴趣区域(ROI)的条码与文字识别功能

Android Jetpack CameraX 实现ROI区域扫描识别方案

核心思路:不需要修改相机预览流本身的输出,仅需将UI层定义的扫描框坐标转换为相机图像帧的对应坐标,要么裁剪对应区域传识别SDK,要么过滤全图识别结果,即可实现仅指定区域识别的需求,性能损耗极低。

1. 坐标映射逻辑实现

相机输出帧的尺寸、方向和UI层预览View的参数不匹配,必须先做坐标转换,否则裁剪区域和预览扫描框完全错位,通用转换代码如下:

fun transformUiRectToImageRect(uiScanRect: RectF, previewView: PreviewView, imageProxy: ImageProxy): Rect {
    val previewWidth = previewView.width.toFloat()
    val previewHeight = previewView.height.toFloat()
    // 判断屏幕方向,竖屏状态下相机帧宽高会互换
    val isPortrait = previewView.display.rotation in listOf(Surface.ROTATION_0, Surface.ROTATION_180)
    val imageWidth = if (isPortrait) imageProxy.height else imageProxy.width
    val imageHeight = if (isPortrait) imageProxy.width else imageProxy.height
    // 计算相机帧到预览View的缩放比例,取最大值保证等比例填充
    val scaleX = imageWidth / previewWidth
    val scaleY = imageHeight / previewHeight
    val scale = max(scaleX, scaleY)
    // 计算等比例缩放后的偏移量,处理预览View边距裁剪的问题
    val offsetX = (imageWidth - previewWidth * scale) / 2
    val offsetY = (imageHeight - previewHeight * scale) / 2
    // 转换UI坐标到相机帧坐标,做边界兼容防止越界
    val left = (uiScanRect.left * scale + offsetX).toInt().coerceAtLeast(0)
    val top = (uiScanRect.top * scale + offsetY).toInt().coerceAtLeast(0)
    val right = (uiScanRect.right * scale + offsetX).toInt().coerceAtMost(imageWidth)
    val bottom = (uiScanRect.bottom * scale + offsetY).toInt().coerceAtMost(imageHeight)
    return Rect(left, top, right, bottom)
}

2. 在图像分析器中实现ROI识别

初始化CameraX的ImageAnalysis用例,在帧回调中处理ROI逻辑,两种实现方式可选:

方案1:裁剪ROI区域后传识别SDK

适合所有支持Bitmap输入的识别SDK,逻辑最通用:

val analysisUseCase = ImageAnalysis.Builder()
    .setTargetResolution(Size(1280, 720))
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .build()
    .also { analysis ->
        analysis.setAnalyzer(Executors.newSingleThreadExecutor()) { imageProxy ->
            // 转换UI扫描框到相机帧坐标
            val roiRect = transformUiRectToImageRect(scanRectF, previewView, imageProxy)
            // 将YUV帧转成Bitmap
            val fullBitmap = Bitmap.createBitmap(imageProxy.width, imageProxy.height, Bitmap.Config.ARGB_8888)
            YuvToRgbConverter(context).yuvToRgb(imageProxy.image!!, fullBitmap)
            // 裁剪ROI区域Bitmap
            val roiBitmap = Bitmap.createBitmap(fullBitmap, roiRect.left, roiRect.top, roiRect.width(), roiRect.height())
            // 传入条码/文字识别SDK处理
            processBarcode(roiBitmap)
            processTextRecognition(roiBitmap)
            // 回收资源
            roiBitmap.recycle()
            fullBitmap.recycle()
            imageProxy.close()
        }
    }
// 最后将analysisUseCase和Preview用例一起绑定到生命周期

方案2:全图识别后过滤ROI范围内的结果

适合ML Kit等自带识别结果坐标返回的SDK,不需要裁剪Bitmap,性能更好:

analysis.setAnalyzer(Executors.newSingleThreadExecutor()) { imageProxy ->
    val roiRect = transformUiRectToImageRect(scanRectF, previewView, imageProxy)
    val inputImage = InputImage.fromMediaImage(imageProxy.image!!, imageProxy.imageInfo.rotationDegrees)
    // 条码识别示例
    BarcodeScanning.getClient().process(inputImage)
        .addOnSuccessListener { barcodes ->
            // 仅保留在ROI范围内的识别结果
            val validResults = barcodes.filter { barcode ->
                barcode.boundingBox?.intersect(roiRect) == true
            }
            // 处理有效结果
        }
        .addOnCompleteListener {
            imageProxy.close()
        }
}

3. 可选优化

  • 若需要相机优先对焦ROI区域,可添加对焦逻辑:
val meteringPointFactory = SurfaceOrientedMeteringPointFactory(previewView.width.toFloat(), previewView.height.toFloat())
val meteringPoint = meteringPointFactory.createPoint(
    scanRectF.centerX(), 
    scanRectF.centerY(),
    scanRectF.width() / previewView.width,
    scanRectF.height() / previewView.height
)
val focusAction = FocusMeteringAction.Builder(meteringPoint, FocusMeteringAction.FLAG_AF)
    .setAutoCancelDuration(2, TimeUnit.SECONDS)
    .build()
camera?.cameraControl?.startFocusAndMetering(focusAction)
  • 扫描框UI可自定义半透明遮罩,无需和CameraX逻辑绑定,只要拿到其在PreviewView中的相对坐标即可。

内容的提问来源于stack exchange,提问作者vignesh prakash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 11:12:00