簡體   English   中英

CameraX 使 ImageAnalysis 的大小與 Preview 相同

[英]CameraX make ImageAnalysis same size as Preview

我希望能夠在預覽時獲得用於分析步驟的准確圖像。 我有預覽用例:

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

在它旁邊我有分析用例配置:

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()

我的預覽是全屏的,所以它的大小是 1440x2560。 但是,如果我嘗試在分析器中從 ImageProxy 獲取尺寸,我會得到 1920x1050,它似乎有不正確的尺寸並且寬度隨高度切換。 為什么會這樣?如何強制我的分析步驟具有與全屏相同的尺寸?

介紹:

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'

我通過FirebaseVisionImage.fromBitmap(bitmap)方法解決了這個問題,其中bitmap - 根據預覽配置手動裁剪 && 旋轉圖像。 步驟是:

  1. 當您設置ImageAnalysis.Builder() && Preview.Builder()時,獲取androidx.camera.view.PreviewView元素的屏幕渲染大小:

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

    然后將大小傳遞給您自己的ImageAnalysis.Analyzer實現(假設它將是viewFinderSize變量,用法見下文)

  2. override fun analyze(mediaImage: ImageProxy){發生時,手動裁剪接收到的ImageProxy 我正在使用另一個關於扭曲的 YUV_420_888 圖像的 SO 問題的片段: https ://stackoverflow.com/a/45926852/2118862

進行裁剪時,請記住ImageAnalysis用例會在預覽用例中接收垂直居中對齊的圖像。 換句話說,接收到的圖像在旋轉后將垂直居中,就好像它在您的預覽區域內一樣(即使您的預覽區域小於傳遞給分析的圖像)。 因此,作物面積應該從垂直中心的兩個方向計算:向上和向下。

作物的垂直尺寸(高度)應在水平尺寸的基礎上手動計算。 這意味着,當您將圖像接收到分析中時,它在預覽區域內具有完整的水平尺寸(預覽內部寬度的 100% 等於分析內部寬度的 100%)。 因此,水平維度上沒有隱藏區域。 這為計算垂直裁剪的大小開辟了道路。 我用下一個代碼完成了這個:

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())

bitmap變量中的最終值 - 是准備傳遞給FirebaseVisionImage.fromBitmap(bitmap)的裁剪圖像

PS。 歡迎改進建議的變體

可能是我遲到了,但這是為我工作的代碼

如果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