拍照时如何使CameraX Preview冻结? [英] How to make CameraX Preview freeze when take a photo?

查看:964
本文介绍了拍照时如何使CameraX Preview冻结?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的自定义CameraX有这样的流程:

I have a flow with my custom CameraX like this:

  • 打开相机预览(实时)
  • 点击按钮拍照
  • 单击该按钮时有一个过程(将路径转换为位图,旋转图像,自动裁剪图像,保存到设备中)
  • 成功运行所有过程后,将图像发送到其他Fragment并将其显示为滑行

问题是running all the process (in step 3)具有delayed 2 seconds且相机预览仍为live(not freezelock)时.如何制作camera preview freeze or lock when running the process?

The question is when running all the process (in step 3) have a delayed 2 seconds and the camera preview still live (not freeze or lock). How to make camera preview freeze or lock when running the process?

这是我在Camera X中运行相机预览的代码:

This is my code to running camera preview in Camera X:

class CameraFragment : Fragment() {

        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.fragment_camera, container, false)
        }

        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)

            viewFinder.post { setupCamera() }
        }

        private fun setupCamera() {
            CameraX.unbindAll()
            CameraX.bindToLifecycle(
                this,
                buildPreviewUseCase(),
                buildImageCaptureUseCase()
            )
        }

        private fun buildPreviewUseCase(): Preview {
            val preview = Preview(
                UseCaseConfigBuilder.buildPreviewConfig(
                    viewFinder.display
                )
            )
            preview.setOnPreviewOutputUpdateListener { previewOutput ->
                updateViewFinderWithPreview(previewOutput)
                correctPreviewOutputForDisplay(previewOutput.textureSize)
            }
            return preview
        }

        private fun buildImageCaptureUseCase(): ImageCapture {
            val capture = ImageCapture(
                UseCaseConfigBuilder.buildImageCaptureConfig(
                    viewFinder.display
                )
            )
            cameraCaptureImageButton.setOnClickListener {
                capture.takePicture(
                    FileCreator.createTempFile(JPEG_FORMAT),
                    Executors.newSingleThreadExecutor(),
                    object : ImageCapture.OnImageSavedListener {
                        override fun onImageSaved(file: File) {
                            // I want make a freeze camera preview when execute this before launch *launchGalleryFragment(path)*
                            val bitmap = BitmapFactory.decodeFile(file.absolutePath)
                            val rotatedBitmap = bitmap.rotate(90)
                            val croppedImage = cropImage(rotatedBitmap, viewFinder, rectangle)
                            val path = saveImage(croppedImage)
                            requireActivity().runOnUiThread {
                                launchGalleryFragment(path)
                            }
                        }

                        override fun onError(
                            imageCaptureError: ImageCapture.ImageCaptureError,
                            message: String,
                            cause: Throwable?
                        ) {
                            Toast.makeText(requireContext(), "Error: $message", Toast.LENGTH_LONG)
                                .show()
                            Log.e("CameraFragment", "Capture error $imageCaptureError: $message", cause)
                        }
                    })
            }
            return capture
        }

        private fun launchGalleryFragment(path: String) {
            val action = CameraFragmentDirections.actionLaunchGalleryFragment(path)
            findNavController().navigate(action)
        }

    }

推荐答案

也许您可以尝试取消绑定预览用例:

Maybe you can try to unbind the preview use case :

版本1.0.0-alpha06:CameraX.unbind(preview);

version 1.0.0-alpha06: CameraX.unbind(preview);

版本> 1.0.0-alpha07:cameraProvider.unbind(preview);

version > 1.0.0-alpha07: cameraProvider.unbind(preview);

根据您的情况,您需要将预览用例保存到一个变量中,然后将其解除绑定:

In your case, you need to save the preview use case into a variable to then unbind it:

// Declare the preview use case variable (as in the CameraXBasic example)
private var preview: Preview? = null

然后实例化变量(就像您所做的那样):

Then instantiate the variable (like you did):

private fun buildPreviewUseCase(): Preview {
    preview = Preview(
        UseCaseConfigBuilder.buildPreviewConfig(
            viewFinder.display
        )
    )
    preview.setOnPreviewOutputUpdateListener { previewOutput ->
        updateViewFinderWithPreview(previewOutput)
        correctPreviewOutputForDisplay(previewOutput.textureSize)
    }
    return preview
}

然后,当您要冻结预览时,只需取消绑定用例:

Then, when you want to freeze the preview just unbind the use case:

CameraX.unbind(preview);

编辑 就像@Billda在这篇文章中所说的: CameraX-当崩溃解除绑定预览UseCase :

EDIT As @Billda said in this post : CameraX - crash when unbinding Preview UseCase :

要冻结预览,请不要取消绑定预览用例.也许有 将来会使用该API,但目前推荐的方法是 存储来自ImageAnalysis的最新帧并将其放入ImageView 重叠预览.

To freeze a preview you should not unbind Preview usecase. There may API for that in the future, but currently the recommended way is to store latest frame from ImageAnalysis and put it to ImageView overlapping the preview.

因此,我决定更新答案,以提供另一个解决方案,该解决方案使用ImageAnalysis(1.0.0-beta02)实现分析器.

So I decided to update my answer to give another solution implementing an analyser with ImageAnalysis (1.0.0-beta02).

1-创建FreezeAnalyzer类:

1- Create the FreezeAnalyzer class:

class FreezeAnalyzer(private val callback: FreezeCallback) : ImageAnalysis.Analyzer {
    private var flag = false

    override fun analyze(image: ImageProxy) {
        if(flag){
            flag = false
            val bitmap = toBitmap(image)
            callback.onLastFrameCaptured(bitmap)
        }
        image.close()
    }

    fun freeze(){
        flag = true
    }

    private fun toBitmap(image: ImageProxy): Bitmap {
        // Convert the imageProxy to Bitmap
        // ref https://stackoverflow.com/questions/56772967/converting-imageproxy-to-bitmap
        // ISSUE, on my android 7 when converting the imageProxy to Bitmap I have a problem with the colors...
        var bitmap = ...

        // Rotate the bitmap
        val rotationDegrees = image.imageInfo.rotationDegrees.toFloat()
        if (rotationDegrees != 0f) {
            val matrix = Matrix()
            matrix.postRotate(rotationDegrees)
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
        }
        return bitmap
    }
}

2- XML

<androidx.camera.view.PreviewView
    android:id="@+id/preview_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />
<ImageView
    android:id="@+id/image_view"
    android:visibility="invisible"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="centerCrop"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

3-初始化imageAnalyser

3- Initialize the imageAnalyser

val resolutionSize = Size(preview_view.width, preview_view.height)

// Set up analyser
imageAnalysis = ImageAnalysis.Builder().apply {
    setTargetResolution(resolutionSize)
    setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
}.build()

val analyzer = FreezeAnalyzer(object : FreezeCallback {
    override fun onLastFrameCaptured(bitmap: Bitmap) {
        runOnUiThread {
            preview_view.visibility = View.INVISIBLE
            image_view.visibility = View.VISIBLE
            image_view.setImageBitmap(bitmap)
        }
    }
})
imageAnalysis.setAnalyzer(executor, analyzer)

4-绑定imageAnalysis用例

4- Bind the imageAnalysis use case

try {
    val camera = cameraProvider.bindToLifecycle(
        this,
        cameraSelector,
        preview,
        imageAnalysis,
        imageCapture
    )
    preview.setSurfaceProvider(preview_view.createSurfaceProvider(camera.cameraInfo))
}

5-捕获图片

btn_capture.setOnClickListener {
    file = File(externalMediaDirs.first(), "${System.currentTimeMillis()}.jpg")
    val outputFileOptions: ImageCapture.OutputFileOptions =
        ImageCapture.OutputFileOptions.Builder(file!!).build()
    analyzer.freeze()
    imageCapture.takePicture(outputFileOptions, executor, onImageSavedCallback)
}

6-发布

btn_release.setOnClickListener {
    preview_view.visibility = View.VISIBLE
    image_view.visibility = View.INVISIBLE
}

我希望它会有所帮助,我不是专家,所以如果您有一些改进,欢迎您!

I hope it helps, I'm not an expert so if you have some improvements you are welcome !

这篇关于拍照时如何使CameraX Preview冻结?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆