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

发布于 2025-01-12 09:09:19 字数 7420 浏览 1 评论 0原文

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

我使用谷歌提供的cameraX库。

我注意到我自己的应用程序捕获的图像的质量与我手机上安装的相机应用程序捕获的图像的质量存在差异。

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

,特别是当我缩放照片时,图像的细节对于我的应用程序拍摄的图像变得更加模糊

(就我自己而言,我的手机是 Google Pixel 5)

请查看这 2 张照片以了解差异

手机摄像头拍摄的图像

我的应用程序的图像

这是我的代码

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

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

我需要你的帮助

I am creating an application which must implement its own camera.

I use the cameraX library provided by google.

I noticed that there is a difference between the quality of the image captured by my own application, and the image captured by the camera application installed on my phone.

although the 2 photos are captured with the same conditions (light, position...)

especially when I zoom the photo, the details of the image become more blurry to the image captured by my application

(in my own case, my phone is Google Pixel 5)

Please see these 2 photos to see the difference

Image by phone camera

Image by my app

And this is my code

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

How can I improve the quality of my images? Is there any thing I should do? is there a special filter or algorithm?

i need your help please

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

两人的回忆 2025-01-19 09:09:19

如果您在 Pixel 上拍照,可能会使用默认摄像头应用程序 (GCam) - 该应用程序在某些 AI 的支持下实现了质量改进。与质量最高的竞争是一项艰巨的任务...尝试与一些第三方拍照,例如 OpenCamera 并将这张图片与您的应用程序获取的图片进行比较

if you took photo on Pixel probably using default cam app (GCam) - this app is fulfilled with quaility improvements backed up by some AI. tough task to comptetite with the biggest in quality... try to take a photo with some 3rd party like OpenCamera and compare this picture with one got by your app

木槿暧夏七纪年 2025-01-19 09:09:19

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

You can use CameraX Extension feature to enable HDR & Low light.
this improves the image quality significantly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文