Android Camera2: Auto Focus and Exposure - android

In my Android camera application I'm using the Camera2 API. The application doesn't show the preview of the Camera, and I've implemented it in a way, when a button on the UI is pressed, it takes an image. But the problem is with auto focus and auto exposure. Simply, I need to camera always focused on the middle of its view. So when building the request, I added following properties:
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
captureBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO);
captureBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
captureBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_START);
But the problem is still the images are not focused.
I have couple of questions:
Do I need to implement some checking in a method inside CameraCaptureSession.CaptureCallback?
I also noticed that by the time onImageAvailable is called in ImageReader.OnImageAvailableListener, the onCaptureProgressed method of CameraCaptureSession.CaptureCallback is not triggered.
What are the points I'm missing here? Do I need to implement a thread to wait until the camera is focused, which will start by when pressing the take picture button.
Please note that there's no camera preview for this application.

Are you sending only a single capture request? Or are you running a repeating request in the background, and then only issuing a high-resolution capture on button press?
The former won't really work - you have to have a flow of requests to have the autoexposure, focus, and white balance algorithms converge to good values. A single capture won't be properly metered or focused.
Please take a look at the Camera2Basic sample; if you replace the TextureView in that sample with just a SurfaceTexture (give it a random texture ID and don't call updateTexImage), then you can have no preview. But it implements focusing and the precapture trigger correctly, which is critical for you here. For one, the triggers must only be set on one request, and then you do need to watch the capture results coming back to see when the exposure / focus state changes to FOCUSED or CONVERGED.
I'd also recommend the CONTINUOUS_PICTURE focus mode instead of AUTO; it's likely to get you a focused image faster.

Related

Does mirroring the (front) camera affect MLKit with CameraX?

You might consider this question a sequel to this other one I've recently asked. I have a custom device with a front camera that is mirrored by default and I would like it to always behave like it was flipped horizontally. Note that the end goal of my app is to perform face, barcode and facemask detection (the last one with a custom .tflite model), and I'm trying to understand if it's possible with the current state of CameraX and the quirks of the device I'm using.
For the preview, I can force PreviewView to use a TextureView by calling PreviewView#implementationMode = PreviewView.ImplementationMode.COMPATIBLE so I can just call PreviewView#setScaleX(-1) and it gets displayed like I want.
For taking pictures, I haven't tried yet but I know I can pass setReversedHorizontal(true) to the ImageCapture.OutputFileOptions used in the ImageCapture.Builder, so the image should be saved in reverse.
For image analysis I really don't know. If the input image is taken directly from the preview stream, then it should still be in its default state because PreviewView#setScaleX(-1) only flips the View on screen, right? So in my Analyzer's analyze() I would need to convert the ImageProxy#image to bitmap, then flip it and pass the result to InputImage.fromBitmap().
Is this everything I need? Is there a better way to do this?

How to set android camera2 parameters to have the best result at text recognizing

I'm creating an android app that allow user to scan the code on a small card (like yu gi oh card).
The problem is that the number I want to read is really small and it's hard to get a good focus to make it clear. So I wanted to set the params to get the best result at closest distance.
At first, I follow this tutorial to create a simple camera preview: https://inducesmile.com/android/android-camera2-api-example-tutorial/
Next I tried to change the camera preview settings to disable auto-focus, it works well, but then I tried to manually set the focus distance, and nothing change.
This is an extract of the code in the camera preview creation methods :
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
//Disable auto-focus
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_OFF);
//Try to make it at the shortest distance (do not work)
captureRequestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, characteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)
I've tried different parameters on the focus distance, but nothing change.
Maybe I'm just making a mistake, and it's not the right way to improve this.
Manual focus control is not a guaranteed feature. Many lower-end devices do not support it, and only support autofocus. You can check if the device has the capability MANUAL_SENSOR. Some cameras are entirely fixed-focus (mostly these are selfie cameras), so those you can't even autofocus.
For your use case, autofocus should work well enough anyway, as long as the small card fills up most of the visible scene.
Note that many devices have a minimum focus distance of 8-10 cm, so you can't hold the card really close and expect to get sharp images of it.

Camera2 API - AF_STATE cannot reach any LOCKED status

From the doc, and the camera2basic example, (This question is based heavily on this camera2basic example)
In captureCallback, captureStillPicture() will be executed after afState reached a locked status, i.e. one of the below:
(1) CONTROL_AF_STATE_NOT_FOCUSED_LOCKED
(2) CONTROL_AF_STATE_FOCUSED_LOCKED
It works, if there is no zooming feature. in captureCallback, afState can always reach either of the above 2 state, therefore captureStillPicutre is always triggered.
However, after I implemented zoom feature:
If I take a picture first, and then zoom, and then try to take a picture again, the second trial cannot reach the lock status. It remains in CONTROL_AF_STATE_PASSIVE_FOCUSED.
If I zoom, and then take the first picture, the first picture can be focused. But if I try again (even without changing zoom level), the second trial cannot reach the lock status. It remains in CONTROL_AF_STATE_PASSIVE_FOCUSED.
If I do not zoom at all, all attempts can reach a locked status.
In addition, I observed that in my test case 2 (Zoom and take a first picture), the camera tried to focus by changing its focus distance (you can observe that the preview changes from blur to clear). But such phenomenon does not happen in second trial.
The code for camera2 is quite long, but you may still look at my code here.
When user taps the shutter button, takePicture() will be executed, and therefore lockFocus() and so on.
Much appreciated if someone can help!!

Android blur surfaceview used in camera

I have a camera preview in my android app. As you all probably know it is implemented by a surfaceview in android.
In my photo app, which allows users to take pictures, I want to blur the camera preview (the surface view) if the user has not logged in yet if the user is logged in, I will display the normal preview (without blur)
Blur as something like
But there seems to be no way to do it
Couple things come to mind but I am not sure how to achieve it
use a blur overlay and place it on top of the surface view, but how do u create such blur overlay?
another approach is to change the attribute of the window, but I can't do it to surfaceview,
getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
So can we create a window overlay the surfaceview and set the flag like that? I don't think so
can someone tell me how to blur a camera preview, which is a surface view
note: I am trying to blur an area which is the output from camera preview, so it is not like I am blurring a static image, the blur area will change depending on where you point your phone camera
The best way to do this is to take a screen shot of the control, apply a blur to it, and then show that image over the top of the original control. This is how the yahoo weather app does it and its how google suggest you do things like this.
Render script does bluring fast. I've also got some code, but it's not currently at hand right now.
These might help:
http://blog.neteril.org/blog/2013/08/12/blurring-images-on-android
http://docs.xamarin.com/recipes/android/other_ux/drawing/blur_an_image_with_renderscript/
I've also read that there are methods built into Android that do this, but the API isn't public so we cannot use it... which sucks.
Although your 2nd option is losing support in later versions of the Android OS, it may be a good option. I would think to bring a window IN FRONT of your surfaceview, and use the blur_behind property of your now new IN FRONT window.
Android API documentation
"
This constant was deprecated in API level 14.
Blurring is no longer supported.
Window flag: blur everything behind this window.
Constant Value: 4 (0x00000004)"
I do have to admit, Im not 100% sure this would work, but its definitely worth a try.
You have to change the camera parameters; in this case with Camera.Parameters.setPictureSize().
The basic workflow here is :
Camera.Parameters cp = mCamera.getParameters(); // get the current params
cp.set...(); // change something
mCamera.setParameters(cp); // write the params back
Make sure that every resolution that you set via this function is supported. You can get a list of the resolutions that are supported on a device via Camera.Parameters.getSupportedPictureSizes(). and check this Camera documentation.

Android toggle camera flash

I use the android camera and allow the user to take stills, but I would also like to also allow the user to toggle the ability to use flash. From off/on/auto
This button will be overlayed on the camera just like in the default android camera application. But I do not want to use that application.
How would I do this? I understand Camera.Parameters, but if I added a button on the layout that added key/value pairs to camera.parameters, would I need to refresh the camera? I will eventually try this (sometimes just typing out problems helps me come up with ideas), but any insight would be appreciated!
You can change the Camera parameters at any time (after you have your camera object).
http://developer.android.com/reference/android/hardware/Camera.Parameters.html
Use whatever settings you want, and attach them to whatever you want your buttons to look like. It's 100% straight forward.
here's a sample from something I did...
Camera.Parameters cp = mCamera.getParameters();
cp.setJpegQuality(100);
cp.setColorEffect(Parameters.SCENE_MODE_PORTRAIT);
cp.setFlashMode(Parameters.FLASH_MODE_ON);
cp.setColorEffect(Parameters.EFFECT_MONO);
setPictureSize(cp);
mCamera.setParameters(cp);
You can call setParameters at any time, and they will take effect immediately.

Categories

Resources