简体   繁体   English

CameraX 使 ImageAnalysis 的大小与 Preview 相同

[英]CameraX make ImageAnalysis same size as Preview

I want to be able to get the exact image for analysis step as I get in preview.我希望能够在预览时获得用于分析步骤的准确图像。 I have preview use case:我有预览用例:

val metrics = DisplayMetrics().also { binding.codeScannerView.display.getRealMetrics(it) }
    val screenAspectRatio = Rational(metrics.widthPixels, metrics.heightPixels)
    val previewConfig = PreviewConfig.Builder().apply {
        setTargetAspectRatio(screenAspectRatio)
    }.build()

And next to it I have analysis use case config:在它旁边我有分析用例配置:

val analyzerConfig = ImageAnalysisConfig.Builder().apply {
        setTargetResolution(Size(metrics.heightPixels, metrics.widthPixels))
        setTargetAspectRatio(screenAspectRatio)
        val analyzerThread = HandlerThread(
                "QrCodeReader").apply { start() }
        setCallbackHandler(Handler(analyzerThread.looper))
        setImageReaderMode(
                ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
    }.build()

My preview is fullscreen so it's size is 1440x2560.我的预览是全屏的,所以它的大小是 1440x2560。 But if I try to get dimensions from ImageProxy in analyzer, I get 1920x1050 which seems to have incorrect dimensions and switched width with height.但是,如果我尝试在分析器中从 ImageProxy 获取尺寸,我会得到 1920x1050,它似乎有不正确的尺寸并且宽度随高度切换。 Why is that and how can I force my analysis step to have same dimensions as full screen?为什么会这样?如何强制我的分析步骤具有与全屏相同的尺寸?

Intro:介绍:

implementation 'androidx.camera:camera-core:1.0.0-alpha10'
implementation 'androidx.camera:camera-camera2:1.0.0-alpha10'
implementation "androidx.camera:camera-lifecycle:1.0.0-alpha10"
implementation "androidx.camera:camera-view:1.0.0-alpha07"
implementation 'com.google.firebase:firebase-ml-vision:24.0.1'
implementation 'com.google.firebase:firebase-ml-vision-barcode-model:16.0.2'

I am solve this issue via the method FirebaseVisionImage.fromBitmap(bitmap) where bitmap - manual cropped && rotated image according to preview configuration.我通过FirebaseVisionImage.fromBitmap(bitmap)方法解决了这个问题,其中bitmap - 根据预览配置手动裁剪 && 旋转图像。 The steps are:步骤是:

  1. when you setup ImageAnalysis.Builder() && Preview.Builder() obtain the on-screen rendered size for androidx.camera.view.PreviewView element:当您设置ImageAnalysis.Builder() && Preview.Builder()时,获取androidx.camera.view.PreviewView元素的屏幕渲染大小:

     previewView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED) val previewSize = Size(previewView.width, previewView.height)

    Then pass the size into your own ImageAnalysis.Analyzer implementation (let's say it will be viewFinderSize variable, usage see below)然后将大小传递给您自己的ImageAnalysis.Analyzer实现(假设它将是viewFinderSize变量,用法见下文)

  2. when override fun analyze(mediaImage: ImageProxy){ occurs, do the manual crop of received ImageProxy .override fun analyze(mediaImage: ImageProxy){发生时,手动裁剪接收到的ImageProxy I am use the snippet from another SO question about distorted YUV_420_888 image: https://stackoverflow.com/a/45926852/2118862我正在使用另一个关于扭曲的 YUV_420_888 图像的 SO 问题的片段: https ://stackoverflow.com/a/45926852/2118862

When you do the cropping, keep in mind that ImageAnalysis use case receive image aligned in vertical-middle basis within your preview use case.进行裁剪时,请记住ImageAnalysis用例会在预览用例中接收垂直居中对齐的图像。 In other words, received image, after rotation will be vertically centred as if it will be inside your preview area (even if your preview area is smaller than the image passed into analysis).换句话说,接收到的图像在旋转后将垂直居中,就好像它在您的预览区域内一样(即使您的预览区域小于传递给分析的图像)。 So, crop area should be calculated in both directions from the vertical center: up and down.因此,作物面积应该从垂直中心的两个方向计算:向上和向下。

The vertical size of the crop (height) should be manually calculated on the horizontal size basis.作物的垂直尺寸(高度)应在水平尺寸的基础上手动计算。 This means, when you receive image into analysis, it has full horizontal size within your preview area (100% of width inside preview is equal 100% of width inside analysis).这意味着,当您将图像接收到分析中时,它在预览区域内具有完整的水平尺寸(预览内部宽度的 100% 等于分析内部宽度的 100%)。 So, no hidden zones in horizontal dimension.因此,水平维度上没有隐藏区域。 This open the way to calculate the size for vertical cropping.这为计算垂直裁剪的大小开辟了道路。 I am done this with next code:我用下一个代码完成了这个:

var bitmap = ... <- obtain the bitmap as suggested in the SO link above
val matrix = Matrix()
matrix.postRotate(90f)
bitmap = Bitmap.createBitmap(bitmap, 0, 0, image.width, image.height, matrix, true)
val cropHeight = if (bitmap.width < viewFinderSize!!.width) {
    // if preview area larger than analysing image
    val koeff = bitmap.width.toFloat() / viewFinderSize!!.width.toFloat()
    viewFinderSize!!.height.toFloat() * koeff
} else {
    // if preview area smaller than analysing image
    val prc = 100 - (viewFinderSize!!.width.toFloat()/(bitmap.width.toFloat()/100f))
    viewFinderSize!!.height + ((viewFinderSize!!.height.toFloat()/100f) * prc)
}

val cropTop = (bitmap.height/2)-((cropHeight)/2)
bitmap = Bitmap.createBitmap(bitmap, 0, cropTop.toInt(), bitmap.width, cropHeight.toInt())

The final value in bitmap variable - is the cropped image ready to pass into FirebaseVisionImage.fromBitmap(bitmap) bitmap变量中的最终值 - 是准备传递给FirebaseVisionImage.fromBitmap(bitmap)的裁剪图像

PS. PS。 welcome to improve the suggested variant欢迎改进建议的变体

May be I am late but here is the code working for me可能是我迟到了,但这是为我工作的代码

Few times if the the cropTop comes as -ve value so whenever the negative value comes you should process image which comes from ImageProxy in other cases you can process cropped bitmap如果cropTop 很少以-ve 值出现,因此每当出现负值时,您应该处理来自 ImageProxy 的图像,在其他情况下,您可以处理裁剪的位图


        val mediaImage = imageProxy.image ?: return
        var bitmap = ImageUtils.convertYuv420888ImageToBitmap(mediaImage)

        val rotationDegrees = imageProxy.imageInfo.rotationDegrees

        val matrix = Matrix()
        matrix.postRotate(rotationDegrees.toFloat())

        bitmap =
            Bitmap.createBitmap(bitmap, 0, 0, mediaImage.width, mediaImage.height, matrix, true)
        val cropHeight = if (bitmap.width < previewView.width) {
            // if preview area larger than analysing image
            val koeff = bitmap.width.toFloat() / previewView.width.toFloat()
            previewView.height.toFloat() * koeff
        } else {
            // if preview area smaller than analysing image
            val prc = 100 - (previewView.width.toFloat() / (bitmap.width.toFloat() / 100f))
            previewView.height + ((previewView.height.toFloat() / 100f) * prc)
        }

        val cropTop = (bitmap.height / 2) - ((cropHeight) / 2)

        if (cropTop > 0) {
            Bitmap.createBitmap(bitmap, 0, cropTop.toInt(), bitmap.width, cropHeight.toInt())
                .also { process(it, imageProxy) }
        } else {
            imageProxy.image?.let { process(it, imageProxy) }
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM