I have some trouble with the onAutoFocus callback of the Android Camera API. In the constructor of my Preview class I set the focus mode to FOCUS_MODE_AUTO and the flash mode to FLASH_MODE_AUTO. The button I present to the user to take a picture has a custom animation attached to it. When the user pressed the button, the animation starts and so does the auto focus:
public void onAnimationStart(Animation animation) {
isAutoFocusing = true;
AutoFocusCallBackImpl autoFocusCallBack = new AutoFocusCallBackImpl();
camera.autoFocus(autoFocusCallBack);
}
Then in the onAutoFocus method I take the picture:
public void onAutoFocus(boolean success, Camera camera) {
if (camera != null) {
try {
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
} catch(Exception e) {
// If something went wrong, we return
// the user to the dashboard.
setResult(Constants.PICTURE_CAMERA_ERROR);
finish();
}
}
}
This works perfectly when there is enough light (so without the flash). In the dark however, the flash goes off and the picture is taken, but it appears that the camera did not focus properly. I know that the onAutoFocus callback is called immediately if auto focus isn't supported by the camera, but that clearly isn't the case here. Is auto focus impossible in the dark (even with the flash)?
This obviously is a hardware issue: To focus automatically, your device needs an image. No image (in the dark) -> no autofocus. There is no way for the camera to tell whether the image is sharp if there is no image, that's why focusing in the dark does not work.
That's why cameras (and I guess some android devices too) have a small light which gets switched on while focusing. But I guess most phones don't have this focus-light :/
Related
I will explain my case.
I'm trying to do an application in which every 5 seconds will take an image, one without flash, and then after 5 seconds one with flash, and repeat this every time. So it will take one without flash, one with flash, one without flash, one with flash... infinitely.
The case is that with my code I can do this in some devices, but the same code won't work in others as I want. i.e:
BQ Aquaris X5 Plus : The no-flash image is correct, but the flash image will be just white.
BQ Aquaris E5 : Won't fire the flash.
How can this be possible, all devices in which I have tried are LEGACY hardware support level for Camera2 API.
This are some important methods in my code (I can't post all code due to char limit). I started from the Google Example:
This setAutoFlash does the mentioned above.
private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
if (mFlashSupported) {
if(phototaken) {
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
}else{
requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
}
}
}
This other one works in some devices and the bq aquaris e5 but doesn't fire the flash in the bq aquaris x5 plus.
private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
if (mFlashSupported) {
if(phototaken) {
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
}else{
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
}
}
}
And my captureStillPicture
private void captureStillPicture() {
try {
final Activity activity = getActivity();
if (null == activity || null == mCameraDevice) {
return;
}
// This is the CaptureRequest.Builder that we use to take a picture.
final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
// Use the same AE and AF modes as the preview.
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
setAutoFlash(captureBuilder);
// Orientation
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session,
#NonNull CaptureRequest request,
#NonNull TotalCaptureResult result) {
showToast("Saved: " + mFile);
Log.d(TAG, mFile.toString());
unlockFocus();
}
};
mCaptureSession.stopRepeating();
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
phototaken = !phototaken;
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
The question is, what am i doing wrong so it doesn't work in all devices? Any help will be great.
There are two levels of control for the flash - manual, and controlled by the auto-exposure routine. You're currently mixing them together.
If you want to fire the flash manually, then you need to set AE_MODE to either AE_MODE_OFF or AE_MODE_ON; not any of the FLASH modes. Then, FLASH_MODE will control whether the flash will be in torch mode, off, or fire once for a given request.
Since you're always leave AE_MODE in one of the FLASH states, what you do to FLASH_MODE should not matter, barring a bug in some specific device.
If you want to guarantee flash firing in every other picture, you need to use AE_MODE_ON_ALWAYS_FLASH for the force-flash photos, and you need to use AE_MODE_ON for the no-flash phoots; don't touch FLASH_MODE.
Right now, with AUTO_FLASH, it's up to the device whether to fire a flash or not, so you'll see different behavior from different devices and lighting conditions - some will fire, some won't.
The other key thing you're not doing is running a precapture sequence; this is essential for flash pictures, because it allows the device to fire the preflash to determine correct flash power, focus, and white balance.
To run precapture, set the AE_MODE as desired, and then set AE_PRECAPTURE_TRIGGER to START for one request. This will transition AE_STATE to PRECAPTURE, and it'll stay there for some number of frames; once AE_STATE is no longer PRECAPTURE, you can issue the actual image capture request. Make sure you keep the AE_MODE consistent throughout this.
The sample app Camera2Basic implements the precapture sequence, so take a look there; it also has some optimizations that skip precapture in case the scene is not dark enough to need flash, but since you want to force-fire flash, that's not relevant to you.
I use following codes to take pictures from the camera view.
captureButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCamera.autoFocus(new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
mCamera.takePicture(null, null, mPicture);
}
});
}
});
Instead of asking users to shoot a picture, now I need to continuously show a smaller part (e.g., 50% width) of the camera picture directly to a view (e.g., ImageView).
How can I get the current content from the camera and operate to get a part of it? I need a fast way, so as to be in a video streaming manner (better if I could directly realize this by some codes with the SurfaceHolder preview configuration).
I don't know if I understand you correctly. You could use a custom view extending SurfaceView to get and show the camera preview (something like this, you will probably have to play around with some parameters). Then you could place that view on your layout.
I'm working on an Android app that uses the camera to preview and take pictures. I use FOCUS_MODE_CONTINUOUS_PICTURE with the galaxy S4 and find that the focusing works very well.
However, on the galaxy S5 the FOCUS_MODE_CONTINUOUS_PICTURE rarely ever finds the focus properly. The camera will zoom into focus, but then zoom back out of focus repeatedly.
Does anyone have an idea of why the FOCUS_MODE_CONTINUOUS_PICTURE works so poorly on the S5, or can anyone confirm whether or not they have the same issue?
I too have experienced these same issues.
The Galaxy S5, and possibly other devices, don't seem to have reliable behavior in continuous picture focus mode. This is very frustrating as a developer, when code works perfectly on most devices, but then along comes the S5 (a very popular device) and we look pretty bad.
After much head scratching, I think I have a solution (more of a workaround) that is working well.
set camera to FOCUS_MODE_CONTINUOUS_PICTURE
in gesture handler for taking a photo (e.g. button tap, touch event), switch camera to FOCUS_MODE_AUTO, then call Camera.autoFocus() in a deferred manner
this provides the nice continuous focus UI during photo preview, but takes the picture in reliable auto-focus mode.
Here is the code:
protected void onTakePicture()
{
// mCamera is the Camera object
// mAutoFocusCallback is a Camera.AutoFocusCallback handler
try
{
// determine current focus mode
Camera.Parameters params = mCamera.getParameters();
if (params.getFocusMode().equals(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
{
mCamera.cancelAutoFocus(); // cancels continuous focus
List<String> lModes = params.getSupportedFocusModes();
if (lModes != null)
{
if (lModes.contains(Camera.Parameters.FOCUS_MODE_AUTO))
{
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // auto-focus mode if supported
mCamera.setParameters(params); // set parameters on device
}
}
// start an auto-focus after a slight (100ms) delay
new Handler().postDelayed(new Runnable() {
public void run()
{
mCamera.autoFocus(mAutoFocusCallback); // auto-focus now
}
}, 100);
return;
}
mCamera.autoFocus(mAutoFocusCallback); // do the focus, callback is mAutoFocusCallback
}
catch (Exception e)
{
Log.e("myApp", e.getMessage());
}
}
please give this a try and report back your results
I am taking a picture in Android (2.3 and greater) that takes a picture using camera.takePicture(). It works great, but I get weird behavior on different devices. On my Nexus One, the image I captured stays frozen for a few seconds before reverting to the preview. On my Transformer, it reverts to the preview almost immediately.
For now, a workaround would be to call camera.stopPreview() in the onShutter() event, but that's still a bit weird, since it's not showing the photo you took, it's showing what the preview saw a split second after you took the picture. On the Transformer, you can even see it "freeze-move-freeze" as it freezes for a split second after taking the picture, starts moving again, then gets to onShutter and freezes when I call stopPreview().
Does anyone know of a setting somewhere, or some code I could call, that would tell the camera how long to hold onto that image before restarting the preview? Or better yet, have it not automatically release the preview at all, and wait until I call startPreview?
on my devices I have to restart the preview manually, it doesn't start up itself after taking a picture. I use a picture callback like
camera.takePicture(null, null, takePictureCallback);
and the callback is
private Camera.PictureCallback takePictureCallback = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera cam) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (camera != null) {
camera.startPreview();
}
canTakePicture = true;
}
}, PHOTO_PREVIEW_LENGTH);
new PhotoProcessor(activity, targetUri).execute(data);
}
};
PhotoProcessor saves the image, PHOTO_PREVIEW_LENGTH is the length in ms for how long is the captured image shown.
We are using an LG Optimus speed and are trying to obtain an image from the camera with our own activity. The Code we are using to do so is:
GetImage(new PictureCallback(){
#Override
public void onPictureTaken(byte[] data, Camera camera) {
camera.startPreview();
bmp = BitmapConversion.convertBmp(data));
}
});
...
public static void GetImage(final PictureCallback jpgCallback) {
GetCamera().autoFocus(new AutoFocusCallback(){
#Override
public void onAutoFocus(boolean success, Camera camera) {
if(success)
GetCamera().takePicture(null, null, jpgCallback);
else
GetImage(jpgCallback);
}
});
}
The images have a considerable worse quality than the images obatained with the native android camera app. Here are 2 example pictures, both taken with a resolution of 640x480 an magnified. As you can see the left picture taken with the native app looks "cleaner" than the right taken with our own application.
Any Ideas?
You don't know what the native app is doing in terms of configuring the camera before taking the image and post-processing after taking the image.
There are many settings available on the camera which are well documented and should be investigated.
You should also be aware that vastly different results exist on using the same method but with the slightest variation in light and focus.
Try looking into the autofocus settings and perhaps do something on autofocus callback.
When comparing the two methods make sure your camera is balanced on something rather than handheld and ensure that the distance and light levels are identical.