Setting target resolution for CameraX not working as in documentation - android

I want to capture photos with fixed resolution (i.e. 1200x1600) using CameraX library.
So according to documentation I can set target resolution for ImageCaptureConfig:
val imageCaptureConfig = ImageCaptureConfig.Builder()
.setLensFacing(CameraX.LensFacing.BACK)
.setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
.setTargetResolution(Size(1200, 1600))
.setTargetAspectRatio(Rational(3,4))
.build()
Documentation describes setTargetResolution method as follows:
Sets the intended output target resolution.
The target resolution attempts to establish a minimum bound for the
image resolution. The actual image resolution will be the closest
available resolution in size that is not smaller than the target
resolution, as determined by the Camera implementation. However, if no
resolution exists that is equal to or larger than the target
resolution, the nearest available resolution smaller than the target
resolution will be chosen.
Correct me if I am wrong, but if device is able to take photos larger than 1200x1600 (e.g. 3024x4032), the output photo will be at least 1200x1600.
Unfortunately in many devices (e.g. Huawei P20 Pro, Samsung A5) the output photo is significantly smaller than 1200x1600, e.g. 480x640. Notice that these devices are able to take really large photos.
Is my ImageCaptureConfig badly configured or this is a bug?

The android documentation say this:
You cannot set both target aspect ratio and target resolution on the same use case. Doing so will throw an IllegalArgumentException when building the config object.
So decide what is mor important for you and choose only one.

It could be a bug that have been recently fixed at AOSP.
refer https://android.googlesource.com/platform/frameworks/support/+/5c1aed8c4c502a74eb4ee6d30fe2089f4afcaf11

When you use .setTargetResolution(Size), the resolution Size should be expressed in the coordinate frame after rotating the supported sizes by the target rotation.
For example, a device with portrait natural orientation in natural target rotation requesting a portrait image may specify 480x640, and the same device, rotated 90 degrees and targeting landscape orientation may specify 640x480.
So this in Portait:
val imageCaptureConfig = ImageCaptureConfig.Builder()
.setTargetResolution(Size(1200, 1600))
Became that in Landscape:
val imageCaptureConfig = ImageCaptureConfig.Builder()
.setTargetResolution(Size(1600, 1200))
Be careful of the orientation of your device:
fun getTargetResolution(): Size {
return when (resources.configuration.orientation) {
Configuration.ORIENTATION_PORTRAIT -> Size(1200, 1600)
Configuration.ORIENTATION_LANDSCAPE -> Size(1600, 1200)
else -> Size(1600, 1200)
}
}
fun setupCamera() {
...
val resolution = getTargetResolution()
val imageCaptureConfig = ImageCaptureConfig.Builder()
.setTargetResolution(resolution)
...
}
It is the same thing with ImageAnalysis and ImagePreview
If you want some documentation, go here

Related

CameraX analysis resolution too low (640x480) but Camera2 can do better (720x1280)

So I have an issue with a device (Alcatel 5033D 1) that's always giving me a resolution of 480x640 for CameraX analysis. This is the last version of the code in which I init it:
private void initCameraAnalysis(Size resolution) {
Log.d(TAG, "initCameraAnalysis: ");
cameraAnalysis = new ImageAnalysis.Builder()
.setTargetResolution(resolution)
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.setImageQueueDepth(0)
.build();
cameraAnalysis.setAnalyzer(
cameraExecutor,
new QualityAnalyzer()
);
}
I just added this part to see if it would help, initially these calls weren't there and they actually don't help with this issue:
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.setImageQueueDepth(0)
The resolution is passed when calling that method as follows, and so I'm requesting 720x1280 that's what I need (using portrait orientation):
initCameraAnalysis(new Size(720, 1280));
Now, this is a low end device and always fallback to 480x640 but I have another app made by a colleague that still uses Camera2 and that one can make 720x1280 with this same device without issue, so I know for sure the device is actually capable of doing 720x1280.
Moreover, I have added an ImageCapture use case and that one can do 720x1280 without issue too, but I need it to do 720x1280 during the analysis.
So I wonder if there'd be any way to force 720x1280 in the analysis use case despite the stubbornness of CameraX not taking it, even if it means using some Camera2 extension or whatever.
Otherwise is likely I'd have to rewrite the whole app using Camera2 instead, which seems like going backwards in time...
Thanks a lot in advance!
I don't know If you have seen it but just in case you did not I would like to point what stated here:
Express the resolution Size in the coordinate frame after rotating the supported sizes by the target rotation. For example, a device with portrait natural orientation in natural target rotation requesting a portrait image may specify 480x640, and the same device, rotated 90 degrees and targeting landscape orientation may specify 640x480.
Maybe also give it a shot with:
val imageAnalysis = ImageAnalysis.Builder()
.setTargetResolution(Size(1280, 720))
.build()

Android Camerax crash on real devices

I started to use CameraX (1.0.8 alpha) library in my Android application and during development on real Samnsung A50 device + emulators all working fine. But when it was release to Play Store - I see a lot of crashes on Pixel 2XL and Nexus 5X devices (I tried my app on emulators for this devices, but all is working fine).
I'm just call bindToLifecle:
Fatal Exception: java.lang.IllegalArgumentException: Can not get supported output size under supported maximum for the format: 34
at androidx.camera.camera2.internal.SupportedSurfaceCombination.getSupportedOutputSizes(SupportedSurfaceCombination.java:29)
at androidx.camera.camera2.internal.Camera2DeviceSurfaceManager.getSuggestedResolutions(Camera2DeviceSurfaceManager.java:29)
at androidx.camera.core.CameraX.calculateSuggestedResolutions(CameraX.java:14)
at androidx.camera.lifecycle.ProcessCameraProvider.bindToLifecycle(ProcessCameraProvider.java)
Does anybody had such issues?
Code for init:
#SuppressLint("RestrictedApi")
private void definePermissionsCallback() {
allPermissionsCheck = Dexter.withActivity(this)
.withPermissions(WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
.withListener(new MultiplePermissionsListener() {
#Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (report.areAllPermissionsGranted()) {
isFileStoragePermissionGiven = true;
isCameraPermissionGiven = true;
SharedPreferences sharedPreferences = getSharedPreferences(APPLICATION_SETTINGS, MODE_PRIVATE);
sharedPreferences.edit().putBoolean(ALLOW_CAMERA, true).apply();
findViewById(R.id.switch_camera).setEnabled(true);
cameraProviderFuture = ProcessCameraProvider.getInstance(MainActivity.this);
cameraProviderFuture.addListener(() -> {
try {
cameraProvider = (ProcessCameraProvider) cameraProviderFuture.get();
bindPreview();
} catch (ExecutionException | InterruptedException e) {
Crashlytics.logException(e);
}
}, ContextCompat.getMainExecutor(MainActivity.this));
return;
}...
void bindPreview() {
cameraProvider.unbindAll();
Preview preview = new Preview.Builder()
.setTargetName("Preview")
.build();
preview.setPreviewSurfaceProvider(previewView.getPreviewSurfaceProvider());
cameraSelector = new CameraSelector.Builder().requireLensFacing(lensFacing).build();
cameraProvider.bindToLifecycle(this, cameraSelector, preview);
}
This may not answer perfectly and I could be wrong, but give following a try:
The Preview instance you are using to bind to life cycle, has the Builder which allows setting either of target resolution or target aspect ratio with setTargetResoltion or setTargetAspectRation.
It calls out that if not set
If not set, the default selected resolution will be the best size match to the device's screen resolution, or to 1080p (1920x1080), whichever is smaller.
And
If not set, resolutions with aspect ratio 4:3 will be considered in higher priority.
Respectively.
Based on the error message
Can not get supported output size under supported maximum for the format
It looks like it's not able to get the output size that it's trying to find for the default values for certain devices. This is possible as the HAL implementation of the Camera is done by OEMs (like Nokia, Huawei etc) and can have support for different supported size. If you want to look at supported resolutions in a given device you can use this app: Camera2Api Probe
Pointer to how Camera X selects automatic resolution
TL;DR;
While the API should provide this support implicitly, considering it in alpha, try to set the Aspect Ratio or the Target Resolution explicitly so it works for most of devices. To make it highly configurable you can query the supported resolution using this api
Note that, I have no link or ownership with the mentioned app Camera2Api, but I used it to query Camera2 information for devices in my job.
You could use this function (written in Kotlin) to get the possible output sizes:
private fun getOutputSizes(lensFacing: Int = CameraCharacteristics.LENS_FACING_BACK): Array<Size>? {
val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
for (cameraId in manager.cameraIdList) {
val characteristics = manager.getCameraCharacteristics(cameraId)
val orientation = characteristics[CameraCharacteristics.LENS_FACING]!!
if (orientation == lensFacing) {
val configurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!
return configurationMap.getOutputSizes(SurfaceTexture::class.java)
}
}
return null
}
And simply try them until one of them is working:
for (outputSize in getOutputSizes()!!) {
try {
CameraX.bindToLifecycle(this, qrCodePreview.useCase, qrCodeImageAnalysis.useCase)
return
}
catch (e: IllegalArgumentException) {}
}
TODO("No valid output size found, handle error ...")
Sometimes this happens when you use the old or new version of lib. Try to change it
From the official documentation:
"The CameraX library is in alpha stage, as its API surfaces aren't yet finalized. We do not recommend using Alpha libraries in production. Libraries should strictly avoid depending on Alpha libraries in production, as their API surfaces may change in source- and binary-incompatible ways."
You can wait for a stable release or use api's of Camera or Camera2.
According to official code:
(outputSizeCandidates.isEmpty() && !isDefaultResolutionSupported) {
throw new IllegalArgumentException(
"Can not get supported output size for the desired output size quality for "
+ "the format: "
+ imageFormat);
}
I've got the same on device with Legacy Camera Support. Hope it helps to find answer.
UPD: It happened because CameraX lib can't find best resolution to fit Camera output for Display resolution. For example:
Display resolution: 1280x720
Closest supported camera resolution: 1920x720
DispRes < CamRes. Failed! Lib can't properly setup size.
Lib works if display resolution smaller than camera resolution.
For example:
Display resolution: 1280x800
Closest supported camera resolution: 1280x720
DispRes > CamRes. Success!

CameraCharacteristics doesn't return all the available resolutions

I'm trying to use the maximum resolution when taking a picture using the new camera2 API. First of all, I try to get the available resolutions using the following code:
Charac:
CameraCharacteristics characteristics = mManager.getCameraCharacteristics(mCameraId);
StreamConfigurationMap streamMap =
characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (streamMap == null) {
throw new RuntimeException("StreamConfigurationMap is null. Should not happen.");
}
streamMap.getOutputSizes(ImageFormat.*); // I replaced the star with all possible values
The issue is this returns the following list of resolutions : [1280x960, 1088x1088, 640x480, 352x288, 176x144, 3264x1836, 3264x2448, 1280x720, 960x720, 720x480, 320x240, 1920x1080, 2400x1080, 1440x1080, 2576x1932, 3264x1468] (biggest is 3264x2448)
However when using the stock camera app (Samsung A70) the picture resolution is surprisingly bigger, ie: 4032x3024.
During investigation I tried to download many camera apps from the store to see what is the max resolution in there case, and all of them returned the same resolution as mine, ie: 3264x2448.
My question is how can the Stock Camera App get a bigger resolution than the rest of us?
Did you check the output of StreamConfigurationMap#getHighResolutionOutputSizes() as well?
Some devices list their highest resolutions there, because they can't maintain >= 20-fps output rate guaranteed by the BURST_CAPTURE capability, which is required for all sizes on the normal size list if you want a FULL-level device. As long as at least 8 MP is listed in normal sizes, the device is compliant with the BURST_CAPTURE rules and higher resolutions can be listed under getHighResolutionOutputSizes.

I can't get higher resolution than 960 * 720 in Image Analysis use case in android

I am working on mobile application that's used to scan Images and process them. I am using the new cameraxAPI and Image analysis use case in it.
The problem is I need high resolution images for my model to work, and I can't get higher than 960*720.
Here's my code that I'm building the analyzer with:
HandlerThread handlerThread = new HandlerThread("ImageAnalysis");
handlerThread.start();
ImageAnalysisConfig config = new ImageAnalysisConfig.Builder()
.setCallbackHandler(new Handler(handlerThread.getLooper()))
.setTargetResolution(new Size(2000,2000))
.setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
.build();
mImageAnalysis = new ImageAnalysis(config);
mImageAnalysis.setAnalyzer(new ImageAnalyzer());
NB : although there's no 2000*2000 resolution but according to the documentation it should bring the nearest higher resolution.
Update : I'm testing with HTC desire 12+ , with API 26.
In my CameraX example, I am trying to set ImageAnalysisConfig with dynamic resolutions as per device with DisplayMetrics of TextureView.
Get the size:
// pull the metrics from our TextureView
// textuewView size : height=match_parent, width=match_parent
val metrics = DisplayMetrics().also { textureView.display.getRealMetrics(it) }
// define the screen size
val screenSize = Size(metrics.widthPixels, metrics.heightPixels)
val screenAspectRatio = Rational(metrics.widthPixels, metrics.heightPixels)
Set in ImageAnalysisConfig :
val analyzerConfig = ImageAnalysisConfig.Builder().apply {
// Use a worker thread for image analysis to prevent glitches
val analyzerThread = HandlerThread("OCR").apply {
start()
}
setCallbackHandler(Handler(analyzerThread.looper))
// we only care about the latest image in the buffer,
setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
setTargetResolution(screenSize)// set target here as screen size
}.build()
In my example, I am using firebase vision API to analysis image frame and identify text with OCR.
I have also tried HTC desire 12+ resolution, which is 720x1440 pixels as a TargetResolution as my case is working fine.
Here is my app code is: https://github.com/pranaypatel512/CameraXDemo
I hope dynamic resolution may help you.

Android camera API blurry image on Samsung devices

After implementing the camera2 API for the inApp camera I noticed that on Samsung devices the images appear blurry. After searching about that I found the Sasmung Camera SDK (http://developer.samsung.com/galaxy#camera). So after implementing the SDK on Samsung Galaxy S7 the images are fine now, but on Galaxy S6 they are still blurry. Someone experienced those kind of issues with Samsung devices?
EDIT:
To complement #rcsumners comment. I am setting autofocus by using
mPreviewBuilder.set(SCaptureRequest.CONTROL_AF_TRIGGER, SCaptureRequest.CONTROL_AF_TRIGGER_START);
mSCameraSession.capture(mPreviewBuilder.build(), new SCameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(SCameraCaptureSession session, SCaptureRequest request, STotalCaptureResult result) {
isAFTriggered = true;
}
}, mBackgroundHandler);
It is a long exposure image where the use has to take an image of a static non moving object. For this I am using the CONTROL_AF_MODE_MACRO
mCaptureBuilder.set(SCaptureRequest.CONTROL_AF_MODE, SCaptureRequest.CONTROL_AF_MODE_MACRO);
and also I am enabling auto flash if it is available
requestBuilder.set(SCaptureRequest.CONTROL_AE_MODE,
SCaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
I am not really an expert in this API, I mostly followed the SDK example app.
There could be a number of issues causing this problem. One prominent one is the dimensions of your output image
I ran Camera2 API and the preview is clear, but the output was quite blurry
val characteristics: CameraCharacteristics? = cameraManager.getCameraCharacteristics(cameraId)
val size = characteristics?.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)?.getOutputSizes(ImageFormat.JPEG) // The issue
val width = imageDimension.width
val height = imageDimension.height
if (size != null) {
width = size[0].width; height = size[0].height
}
val imageReader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 5)
The code below was returning a dimension about 245*144 which was way to small to be sent to the image reader. Some how the output was stretching the image making it end up been blurry. Therefore I removed this line below.
val size = characteristics?.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)?.getOutputSizes(ImageFormat.JPEG) // this was returning a small
Setting the width and height manually resolved the issue.
You're setting the AF trigger for one frame, but then are you waiting for AF to complete? For AF_MODE_MACRO (are you verifying the device lists support for this AF mode?) you need to wait for AF_STATE_FOCUSED_LOCKED before the image is guaranteed to be stable and sharp. (You may also receive NOT_FOCUSED_LOCKED if the AF algorithm can't reach sharp focus, which could be because the object is just too close for the lens, or the scene is too confusing)
On most modern devices, it's recommended to use CONTINUOUS_PICTURE and not worry about AF triggering unless you really want to lock focus for some time period. In that mode, the device will continuously try to focus to the best of its ability. I'm not sure all that many devices support MACRO, to begin with.

Categories

Resources