【问题标题】:Convert CameraX Captured ImageProxy to Bitmap将 CameraX 捕获的 ImageProxy 转换为位图
【发布时间】:2021-12-01 01:33:01
【问题描述】:

我正在使用 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)
    }

}

【问题讨论】:

    标签: android android-camerax


    【解决方案1】:

    所以解决方案是向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)
    }
    

    【讨论】:

      【解决方案2】:

      稍作修改的版本。在Closable ImageProxy 上使用inline 函数use

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

      【讨论】:

      • @Bender super.onCaptureSuccess 它会关闭图像,因此在获取图像缓冲区之前检查它是否未被调用。
      • @Blackbelt 一年后仍然没有其他出路,还是我错过了什么?
      【解决方案3】:

      Backbelt的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);
      }
      

      【讨论】:

        【解决方案4】:

        这是最安全的方法,使用 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)
        

        【讨论】:

          【解决方案5】:

          目前有第二个版本的takePicture 方法(CameraX 版本 1.0.0-beta03)。它提供several ways 来保存图像(OutputStreamFile 在您的情况下可能有用)。

          如果您仍想将 ImageProxy 转换为 Bitmap here is 我对类似问题的回答,这给出了此转换的正确实现。

          【讨论】:

            【解决方案6】:

            请看看这个answer。将其应用于您的问题所需的只是从 ImageProxy 中获取 Image

            Image img = imaget.getImage();
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2020-09-04
              • 2020-08-24
              • 2020-09-30
              • 2022-08-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多