如何使用 android cameraX 库提高图像质量?

How to increase image quality with android cameraX library?

我正在创建一个必须实现自己的相机的应用程序。

我使用google提供的cameraX库。

我注意到我自己的应用程序捕获的图像质量与我 phone 上安装的相机应用程序捕获的图像质量不同。

虽然两张照片是在相同的条件下拍摄的(光线、位置...)

尤其是当我缩放照片时,图像的细节变得比我的应用程序捕获的图像更加模糊

(在我自己的例子中,我的 phone 是 Google Pixel 5)

请看这两张照片,看看有什么不同

Image by phone camera

Image by my app

这是我的代码

/**
 *  Initialize CameraX, and prepare to bind the camera use cases
 */
private fun setupCamera()
{
    val cameraProviderFuture : ListenableFuture<ProcessCameraProvider> = ProcessCameraProvider.getInstance(this)
    
    cameraProviderFuture.addListener({
        
        cameraProvider = cameraProviderFuture.get()
        
        lensFacing = when
        {
            hasBackCamera() -> CameraSelector.LENS_FACING_BACK
            hasFrontCamera() -> CameraSelector.LENS_FACING_FRONT
            else -> throw IllegalStateException("Back and front camera are unavailable")
        }
        
        bindCameraUseCases()
        setupCameraGestures()
        
    }, ContextCompat.getMainExecutor(this))
}



/**
 *  Declare and bind preview, capture and analysis use cases.
 */
private fun bindCameraUseCases()
{
    lifecycleScope.launch {
        
        val cameraProvider : ProcessCameraProvider = cameraProvider ?: throw IllegalStateException("Camera initialization failed.")
        
        // Try to apply extensions like HDR, NIGHT ##########################################
        
        val extensionsManager : ExtensionsManager = ExtensionsManager.getInstanceAsync(this@ImageCaptureActivity, cameraProvider).await()
        
        val defaultCameraSelector : CameraSelector = CameraSelector.Builder()
            .requireLensFacing(lensFacing)
            .build()
        
        val finalCameraSelector : CameraSelector = if (extensionsManager.isExtensionAvailable(defaultCameraSelector, ExtensionMode.AUTO))
        {
            extensionsManager.getExtensionEnabledCameraSelector(defaultCameraSelector, ExtensionMode.AUTO)
        }
        else
        {
            defaultCameraSelector
        }
        
        
        // Get screen metrics used to setup camera for full screen resolution
        val metrics : DisplayMetrics = resources.displayMetrics
        
        val screenAspectRatio : Int = aspectRatio(metrics.widthPixels, metrics.heightPixels)
        
        val rotation : Int = binding.cameraPreview.display.rotation
        
        
        preview = Preview.Builder()
            // We request aspect ratio but no resolution
            .setTargetAspectRatio(screenAspectRatio)
            // Set initial target rotation
            .setTargetRotation(rotation)
            .build()
        
        imageCapture = ImageCapture.Builder()
            // We request aspect ratio but no resolution to match preview config, but letting
            // CameraX optimize for whatever specific resolution best fits our use cases
            .setTargetAspectRatio(screenAspectRatio)
            // Set initial target rotation, we will have to call this again if rotation changes
            // during the lifecycle of this use case
            .setTargetRotation(rotation)
            .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
            .setJpegQuality(100)
            .build()
        
        imageAnalyzer = ImageAnalysis.Builder()
            // We request aspect ratio but no resolution
            .setTargetAspectRatio(screenAspectRatio)
            .build()
        
        imageAnalyzer?.setAnalyzer(cameraExecutor, LuminosityAnalyzer {})
        
        // Must unbind the use-cases before rebinding them
        cameraProvider.unbindAll()
        
        try
        {
            // A variable number of use-cases can be passed here -
            // camera provides access to CameraControl & CameraInfo
            camera = cameraProvider.bindToLifecycle(this@ImageCaptureActivity, finalCameraSelector, preview, imageCapture, imageAnalyzer)
            
            // Attach the viewfinder's surface provider to preview use case
            preview?.setSurfaceProvider(binding.cameraPreview.surfaceProvider)
        }
        catch (exception : Exception)
        {
            exception.printStackTrace()
        }
    }
}



/**
 *  [androidx.camera.core.ImageAnalysisConfig] requires enum value of [androidx.camera.core.AspectRatio].
 *  Currently it has values of 4:3 & 16:9.
 *
 *  Detecting the most suitable ratio for dimensions provided in @params by counting absolute
 *  of preview ratio to one of the provided values.
 *
 *  @param width - preview width
 *  @param height - preview height
 *  @return suitable aspect ratio
 */
private fun aspectRatio(width : Int, height : Int) : Int
{
    val previewRatio : Double = max(width, height).toDouble() / min(width, height)
    
    return if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE))
    {
        AspectRatio.RATIO_4_3
    }
    else
    {
        AspectRatio.RATIO_16_9
    }
}



fun captureImage()
{
    if (!permissionsOk()) return
    
    // Get a stable reference of the modifiable image capture use case
    imageCapture?.let { imageCapture ->
        
        // Create output file to hold the image
        val photoFile : File = storageUtils.createFile(
            baseFolder = getOutputPath(),
            fileName = System.currentTimeMillis().toString(),
            fileExtension = StorageUtils.PHOTO_EXTENSION)
        
        // Setup image capture metadata
        val metadata : Metadata = Metadata().also {
            // Mirror image when using the front camera
            it.isReversedHorizontal = lensFacing == CameraSelector.LENS_FACING_FRONT
            it.location = locationManager.lastKnownLocation
        }
        
        // Create output options object which contains file + metadata
        val outputOptions : ImageCapture.OutputFileOptions = ImageCapture.OutputFileOptions.Builder(photoFile)
            .setMetadata(metadata)
            .build()
        
        imagesAdapter.addImage(photoFile)
        
        // Setup image capture listener which is triggered after photo has been taken
        imageCapture.takePicture(outputOptions, cameraExecutor, object : ImageCapture.OnImageSavedCallback
        {
            override fun onImageSaved(output : ImageCapture.OutputFileResults)
            {
                val savedUri : Uri = output.savedUri ?: return
                
                StorageUtils.showInGallery(savedUri.path)
                
                binding.list.post {
                    imagesAdapter.addImage(savedUri.toFile())
                    binding.list.smoothScrollToPosition(imagesAdapter.itemCount)
                }
            }
            
            override fun onError(exception : ImageCaptureException)
            {
                exception.printStackTrace()
            }
        })
        
        binding.cameraPreview.postDelayed({
            binding.backgroundEffect.isVisible = true
            binding.cameraPreview.postDelayed({
                binding.backgroundEffect.isVisible = false
            }, AppUtils.VERY_FAST_ANIMATION_MILLIS)
        }, AppUtils.FAST_ANIMATION_MILLIS)
    }
}

如何提高图像质量?有什么我应该做的吗?是否有特殊的过滤器或算法?

我需要你的帮助

如果您在 Pixel 上拍摄照片可能使用默认的相机应用程序 (GCam) - 此应用程序实现了由某些 AI 支持的质量改进。与最高质量竞争的艰巨任务...尝试与 OpenCamera 等第 3 方合影,并将这张照片与您的应用

获得的照片进行比较

您可以使用 CameraX Extension 功能启用 HDR 和弱光。 这显着提高了图像质量。