I want to get the best quality for square aspect ratio and setup the next preview and capture configs for CameraX.
val SQUARE_ASPECT_RATIO = Rational(1, 1)
val previewConfig = PreviewConfig.Builder().apply {
setTargetAspectRatio(SQUARE_ASPECT_RATIO)
setTargetRotation(viewFinder.display.rotation)
}.build()
preview = Preview(previewConfig)
val imageCaptureConfig = ImageCaptureConfig.Builder().apply {
setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
setTargetAspectRatio(SQUARE_ASPECT_RATIO)
setTargetRotation(viewFinder.display.rotation)
}.build()
imageCapture = ImageCapture(imageCaptureConfig)
CameraX.bindToLifecycle(this, preview, imageCapture)
CameraX chooses 352x288px resolution, so result image resolution equals 288x288px.
From documentation it should be the highest resolution available for current device, but it is not.
Tested on emulator and Google Pixel 3.
Related
we are developing an android app which uses camerax api for video recording.We tried to capture 60 fps video and for this we extended camera2 feature in our code.Here is a snippet of our code
private fun startCameraatf60() {
viewBinding.flash.isChecked=false
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener(Runnable {
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
val preview = Preview.Builder().apply {
setTargetResolution(Size(1080,1920))
}
val exti = Camera2Interop.Extender(preview)
.setCaptureRequestOption(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_USE_SCENE_MODE)
.setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(60,60))
val s = preview.build()
.also {
it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider)
}
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
val recorder = Recorder.Builder()
.setQualitySelector(QualitySelector.from(Quality.FHD))
.build()
videoCapture = VideoCapture.withOutput(recorder)}
But the main problem when 60 fps is being used ,video size(in mb) captured by app is far less than the video size which are captured by device's default camera.Through the app captured video size is around 7 mb and by device's default camera video size is around 50 mb.Can anyone please help us to resolve this issue?
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
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
You can use CameraX Extension feature to enable HDR & Low light.
this improves the image quality significantly.
I've set up the CameraX to use the the back facing camera requireLensFacing(CameraSelector.LENS_FACING_BACK), but testing on a phone with multiple cameras, it uses the wide angle one. How can I let it use the regular camera instead?
https://developer.android.com/training/camerax
val cameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
val preview = Preview.Builder()
.setTargetResolution(Size(binding.preview.width, binding.preview.height))
.build()
val imageAnalysis = ImageAnalysis.Builder()
.setTargetResolution(Size(binding.preview.width, binding.preview.height))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
.also {
it.setAnalyzer(cameraExecutor, analyzer)
}
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(viewLifecycleOwner, cameraSelector, preview, imageAnalysis).also { camera ->
camera.cameraControl.setZoomRatio(2F)
preview.setSurfaceProvider(binding.preview.createSurfaceProvider(camera.cameraInfo))
}
I am trying to use CameraX library to capture image using front camera. But when the camera is launched, preview is showing nothing but black screen. Here is the configurations:
val previewConfig = PreviewConfig.Builder().apply {
setTargetResolution(Size(640, 480))
setLensFacing(CameraX.LensFacing.FRONT)
}.build()
preview = Preview(previewConfig)
preview.setOnPreviewOutputUpdateListener {
val parent = viewFinder.parent as ViewGroup
parent.removeView(viewFinder)
parent.addView(viewFinder, 0)
viewFinder.surfaceTexture = it.surfaceTexture
updateTransform()
}
val imageCaptureConfig = ImageCaptureConfig.Builder()
.apply {
setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
}.build()
imageCapture = ImageCapture(imageCaptureConfig)
val analyzerConfig = ImageAnalysisConfig.Builder().apply {
setImageReaderMode(
ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
}.build()
analyzerUseCase = ImageAnalysis(analyzerConfig).apply {
setAnalyzer(executor, LuminosityAnalyzer())
}
CameraX.bindToLifecycle(this, preview, imageCapture)
But it's working well with setLensFacing(CameraX.LensFacing.BACK). Also if i remove ImageCapture object from bindToLifeCyle method, i can see a preview with the front facing camera.
CameraX.bindToLifecycle(this, preview, /*imageCapture*/)
Please advise.
You also need to set setLensFacing to front for imageCaptureConfig.
I was also facing the same issue , but your question solved my issue :p
I'm following the CameraX codelab and I'm getting a wrong aspect ratio on the preview even using setTargetAspectRatio and setTargetResolution methods.
private fun startCamera() {
// Create configuration object for the viewfinder use case
val previewConfig = PreviewConfig.Builder().apply {
setTargetAspectRatio(Rational(1, 1))
setTargetResolution(Size(640, 640))
}.build()
...
And the layout is using a hardcoded size as presented in the codelab.
<TextureView
android:id="#+id/view_finder"
android:layout_width="640px"
android:layout_height="640px"
...
It would be nice if the library had CameraTextureView and a property android:scaleType (similar to the existing for the ImageView) to adjust the preview to the preview size.
did you try it?
val metrics = DisplayMetrics().also { viewFinder.display.getRealMetrics(it) }
val screenSize = Size(metrics.widthPixels, metrics.heightPixels)
val screenAspectRatio = Rational(metrics.widthPixels, metrics.heightPixels)
val viewFinderConfig = PreviewConfig.Builder().apply {
//...
setTargetResolution(screenSize)
setTargetAspectRatio(screenAspectRatio)
setTargetRotation(viewFinder.display.rotation)
}.build()
val preview = AutoFitPreviewBuilder.build(viewFinderConfig, viewFinder)
And AutoFitPreviewBuilder you can find here:
https://gist.github.com/yevhenRoman/90681822adef43350844464be95d23f1
I would recommend you to set width and height for your TextureView using dp or constaraints.
Let me know if it works for you, thanks!
https://stackoverflow.com/a/49449986/9397052 there is a solution for a similar problem. After you decide on a resolution, don't use setTargetAspectRatio function; instead you should only use setTargetResolution. Then it should work the same.
According to the official Android documentation:
"It is not allowed to set both target aspect ratio and target resolution on the same use case."
Although the compiler does not throw an error if you attempt to do this, unexpected results can occur.
You can set the aspect ratio of a TextureView with Matrix like this:
Matrix txform = new Matrix();
textureView.getTransform(txform);
txform.setScale((float) = videoWidth / viewWidth, (float) videoHeight / viewHeight);// aspect ratio
textureView.setTransform(txform); // apply matrix