旋转的 Android CameraX 图像

Nou*_*tti 10 android image-rotation android-orientation android-camera2 android-camerax

我已经按照 Google CameraX代码实验室来实现自定义相机。相机预览很好,但是当我在旋转图像捕获图像后拍摄图像时。我正在以纵向模式拍摄图像,但保存的图像是横向的。这是配置相机的方法

private fun startCamera() {

    val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

    cameraProviderFuture.addListener(Runnable {
        // Used to bind the lifecycle of cameras to the lifecycle owner
        val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

        // Preview
        val preview = Preview.Builder()
            .setTargetRotation(this.windowManager.defaultDisplay.rotation)
            .build()
            .also {
                it.setSurfaceProvider(viewFinder.createSurfaceProvider())
            }

        imageCapture = ImageCapture.Builder()
            .setTargetRotation(this.windowManager.defaultDisplay.rotation)
            .build()

        val imageAnalyzer = ImageAnalysis.Builder()
            .build()
            .also {
                it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
                    Log.d(TAG, "Average luminosity: $luma")
                })
            }

        // Select back camera as a default
        val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

        try {
            // Unbind use cases before rebinding
            cameraProvider.unbindAll()

            // Bind use cases to camera
            cameraProvider.bindToLifecycle(
                this, cameraSelector, preview, imageCapture, imageAnalyzer)

        } catch(exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
        }

    }, ContextCompat.getMainExecutor(this))
}
Run Code Online (Sandbox Code Playgroud)

这是捕获图像的方法:

private fun takePhoto() {
    val imageCapture = imageCapture ?: return

    // Create time-stamped output file to hold the image
    val photoFile = File(
        outputDirectory,
        SimpleDateFormat(FILENAME_FORMAT, Locale.US
        ).format(System.currentTimeMillis()) + ".jpg")

    // Create output options object which contains file + metadata
    val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

    // Set up image capture listener, which is triggered after photo has
    // been taken
    imageCapture.takePicture(
        outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
            override fun onError(exc: ImageCaptureException) {
                Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
            }

            override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                val savedUri = Uri.fromFile(photoFile)
                val msg = "Photo capture succeeded: $savedUri"
                val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, savedUri)
                ivCapturedImage.setImageBitmap(bitmap)
                setCaptureUI(false)
                Log.d(TAG, msg)
            }
        })
}
Run Code Online (Sandbox Code Playgroud)

使用 EXIF 拍摄后,我需要自己旋转图像还是可以在配置相机时修复它?

Xi *_*ang 5

默认情况下,ImageCapture 将捕获的方向设置为显示旋转。如果图像保存到磁盘,旋转将在 EXIF 中。

您的设备是否处于锁定纵向模式?在这种情况下,显示旋转与设备的方向不匹配,您需要自己设置目标旋转。例子。

// The value is whatever the display rotation should be, if the device orientation is not locked.
imageCapture.setTargetRotation(...) 
Run Code Online (Sandbox Code Playgroud)

或者,您可以简单地使用LifecycleCameraController API。它为您处理旋转并以所见即所得的方式使所有用例保持一致。

  • 我对 LifecycleCameraController 的一个问题是缺少样板代码;API 描述页面中的内容不足以开始使用,并且在 Android 应用程序中通过反复试验进行编程非常耗时...我真的很感谢对此的 Codelab 扩展。我会检查官方的cameraXsample,看看是否有帮助。 (2认同)
  • 感谢您的链接;但据我了解,CameraX 不喜欢干预图像数据,因此它唯一做的就是设置 EXIF 元数据。最后我仍然使用 ProcessCameraProvider 类,在调用 takePicture() 之前设置目标旋转,然后手动从保存的 JPEG 中读取 EXIF 数据,并相应地旋转图片以获得直立图像。我会将其添加为问题的单独答案,尽管我希望 CameraX 负责旋转图像而不依赖于 EXIF 元数据。 (2认同)

Pin*_*its 3

我也面临着同样的情况。我用 hacky 的方式解决了这个问题。

我的解决方案是:

    fun Bitmap.rotate(degrees: Float): Bitmap {
    val matrix = Matrix().apply { postRotate(degrees) }
    return Bitmap.createBitmap(this, 0, 0, width, height, matrix, true)
    }
Run Code Online (Sandbox Code Playgroud)

用法 :

imageViewCapturedImage.setImageBitmap(bitmap?.rotate(90F))
Run Code Online (Sandbox Code Playgroud)