Как заставить CameraX Preview зависать при съемке фотографии? - PullRequest
1 голос
/ 09 января 2020

У меня есть поток с моей пользовательской камерой CameraX, такой как:

  • Открыть предварительный просмотр камеры (в режиме реального времени)
  • Нажмите кнопку, чтобы сделать фотографию
  • Пройдите процесс при нажатии на эту кнопку (преобразовать путь в растровое изображение, повернуть изображение, автоматически обрезать изображение, сохранить на устройстве)
  • После успешного завершения всего процесса отправьте изображение в другой фрагмент и отобразите его в виде глиссады.

Вопрос в том, когда running all the process (in step 3) имеет delayed 2 seconds и предварительный просмотр камеры все еще live (not freeze или lock). Как сделать camera preview freeze or lock when running the process?

Вот мой код для запуска предварительного просмотра камеры в 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)
        }

    }

1 Ответ

2 голосов
/ 10 января 2020

Возможно, вы можете попытаться отменить привязку варианта использования:

версия 1.0.0-alpha06: CameraX.unbind(preview);

версия> 1.0.0-alpha07: cameraProvider.unbind(preview);

В вашем случае вам нужно сохранить вариант использования предварительного просмотра в переменную, чтобы затем отсоединить его:

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

Затем создать экземпляр переменной (как вы сделали):

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

Затем, когда вы хотите заморозить предварительный просмотр, просто отсоедините сценарий использования:

CameraX.unbind(preview);

РЕДАКТИРОВАТЬ Как сказал @Billda в этом посте: CameraX - cra sh когда предварительный отмена предварительного просмотра UseCase :

Чтобы заморозить предварительный просмотр, не следует отменять привязку варианта использования предварительного просмотра. В будущем может быть API для этого, но в настоящее время рекомендуемый способ - сохранить последний кадр из ImageAnalysis и поместить его в ImageView, перекрывая предварительный просмотр.

Поэтому я решил обновить свой ответ, чтобы дать другое решение реализация анализатора с помощью ImageAnalysis (1.0.0-beta02).

1- Создайте класс FreezeAnalyzer:

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

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. Привязайте изображение. Случай использования анализа

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
}

Надеюсь, это поможет, я не эксперт, поэтому, если у вас есть какие-то улучшения, добро пожаловать!

...