将 CameraX 捕获的 ImageProxy 转换为位图

Ste*_*goo 6 android android-camerax

我正在使用 CameraX 并且很难将捕获的 ImageProxy 转换为位图。经过搜索和尝试,我制定了一个解决方案。后来我发现它不是最佳的,所以我改变了设计。这迫使我放弃工作时间。

由于我(或其他人)将来可能需要它,因此我决定将其作为问题发布在这里并发布和回答以供参考和审查。如果您有更好的答案,请随时添加更好的答案。

相关代码是:

class ImagePickerActivity : AppCompatActivity() {
    private var width = 325
    private var height = 205

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_image_picker)

        view_finder.post { startCamera() }
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private fun startCamera() {
        // Create configuration object for the viewfinder use case
        val previewConfig = PreviewConfig.Builder().apply {
            setTargetAspectRatio(Rational(1, 1))
            //setTargetResolution(Size(width, height))
            setLensFacing(CameraX.LensFacing.BACK)
            setTargetAspectRatio(Rational(width, height))
        }.build()

        }

        // Create configuration object for the image capture use case
        val imageCaptureConfig = ImageCaptureConfig.Builder()
            .apply {
                setTargetAspectRatio(Rational(1, 1))
                // We don't set a resolution for image capture instead, we
                // select a capture mode which will infer the appropriate
                // resolution based on aspect ration and requested mode
                setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
            }.build()

        // Build the image capture use case and attach button click listener
        val imageCapture = ImageCapture(imageCaptureConfig)
        capture_button.setOnClickListener {

            imageCapture.takePicture(object : ImageCapture.OnImageCapturedListener() {
                override fun onCaptureSuccess(image: ImageProxy?, rotationDegrees: Int) {
                        //How do I get the bitmap here?
                        //imageView.setImageBitmap(someBitmap)
                }

                override fun onError(useCaseError: ImageCapture.UseCaseError?, message: String?, cause: Throwable?) {
                    val msg = "Photo capture failed: $message"
                    Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
                    Log.e(localClassName, msg)
                    cause?.printStackTrace()
                }
            })
        }
        CameraX.bindToLifecycle(this, preview, imageCapture)
    }

}
Run Code Online (Sandbox Code Playgroud)

Pep*_*ppz 9

这是最安全的方法,使用 MLKit 自己的实现。已在 MLKit 版本 1.0.1 上进行测试和运行

import com.google.mlkit.vision.common.internal.ImageConvertUtils;

Image mediaImage = imageProxy.getImage();
InputImage image = InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees());
Bitmap bitmap = ImageConvertUtils.getInstance().getUpRightBitmap(image)
Run Code Online (Sandbox Code Playgroud)


Ste*_*goo 8

所以解决方案是添加扩展方法Image,这里是代码

class ImagePickerActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_image_picker)
    }

    private fun startCamera() {

        val imageCapture = ImageCapture(imageCaptureConfig)
        capture_button.setOnClickListener {

            imageCapture.takePicture(object : ImageCapture.OnImageCapturedListener() {
                override fun onCaptureSuccess(image: ImageProxy?, rotationDegrees: Int) {
                    imageView.setImageBitmap(image.image?.toBitmap())
                }
                //.....
            })
        }
    }

}

fun Image.toBitmap(): Bitmap {
    val buffer = planes[0].buffer
    buffer.rewind()
    val bytes = ByteArray(buffer.capacity())
    buffer.get(bytes)
    return BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
}
Run Code Online (Sandbox Code Playgroud)


Bla*_*elt 7

稍微修改的版本。使用该inline功能useClosable ImageProxy

imageCapture.takePicture(
           object : ImageCapture.OnImageCapturedListener() {
               override fun onCaptureSuccess(image: ImageProxy?, rotationDegrees: Int) {
                     image.use { image ->
                           val bitmap: Bitmap? = image?.let {
                                imageProxyToBitmap(it)
                            } ?: return
                      }
          }
       })

  private fun imageProxyToBitmap(image: ImageProxy): Bitmap {
        val buffer: ByteBuffer = image.planes[0].buffer
        val bytes = ByteArray(buffer.remaining())
        buffer.get(bytes)
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
    } 
Run Code Online (Sandbox Code Playgroud)


Nis*_*nga 6

Backbelt's Answer 的Java 实现。

private Bitmap imageProxyToBitmap(ImageProxy image) {
    ByteBuffer buffer = image.getPlanes()[0].getBuffer();
    byte[] bytes = new byte[buffer.remaining()];
    buffer.get(bytes);
    return BitmapFactory.decodeByteArray(bytes,0,bytes.length,null);
}
Run Code Online (Sandbox Code Playgroud)