Thursday, January 6, 2011

Start Camera auto-focusing, autoFocus()

To start auto-focusing for Android camera, simple call autoFocus() method of the camera object, and registers a callback function to run when the camera is focused. This method is only valid when preview is active (between startPreview() and before stopPreview()).

Start Camera auto-focusing, autoFocus()

Callers should check getFocusMode() to determine if this method should be called. If the camera does not support auto-focus, it is a no-op and onAutoFocus(boolean, Camera) callback will be called immediately.

If your application should not be installed on devices without auto-focus, you must declare that your application uses auto-focus with the <uses-feature> manifest element.

If the current flash mode is not FLASH_MODE_OFF, flash may be fired during auto-focus, depending on the driver and camera hardware.

Continuous from last exercise "Save the camera image using MediaStore".

Modify control.xml, define id for the background of the layout. Such that we can start auto-focus when user click on the background.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/background"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="bottom"
>
<Button
android:id="@+id/takepicture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" * Take Picture "
android:layout_gravity="right"
android:layout_margin="10px"
/>
</LinearLayout>


Modify AndroidCamera.java to call camera.autoFocus(myAutoFocusCallback), and register the AutoFocusCallback.
package com.exercise.AndroidCamera;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;

import android.app.Activity;
import android.content.ContentValues;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore.Images.Media;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;

public class AndroidCamera extends Activity implements SurfaceHolder.Callback{

Camera camera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
boolean previewing = false;
LayoutInflater controlInflater = null;

Button buttonTakePicture;

final int RESULT_SAVEIMAGE = 0;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

getWindow().setFormat(PixelFormat.UNKNOWN);
surfaceView = (SurfaceView)findViewById(R.id.camerapreview);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

controlInflater = LayoutInflater.from(getBaseContext());
View viewControl = controlInflater.inflate(R.layout.control, null);
LayoutParams layoutParamsControl
= new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
this.addContentView(viewControl, layoutParamsControl);

buttonTakePicture = (Button)findViewById(R.id.takepicture);
buttonTakePicture.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
camera.takePicture(myShutterCallback,
myPictureCallback_RAW, myPictureCallback_JPG);
}});

LinearLayout layoutBackground = (LinearLayout)findViewById(R.id.background);
layoutBackground.setOnClickListener(new LinearLayout.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub

buttonTakePicture.setEnabled(false);
camera.autoFocus(myAutoFocusCallback);
}});
}

AutoFocusCallback myAutoFocusCallback = new AutoFocusCallback(){

@Override
public void onAutoFocus(boolean arg0, Camera arg1) {
// TODO Auto-generated method stub
buttonTakePicture.setEnabled(true);
}};

ShutterCallback myShutterCallback = new ShutterCallback(){

@Override
public void onShutter() {
// TODO Auto-generated method stub

}};

PictureCallback myPictureCallback_RAW = new PictureCallback(){

@Override
public void onPictureTaken(byte[] arg0, Camera arg1) {
// TODO Auto-generated method stub

}};

PictureCallback myPictureCallback_JPG = new PictureCallback(){

@Override
public void onPictureTaken(byte[] arg0, Camera arg1) {
// TODO Auto-generated method stub
/*Bitmap bitmapPicture
= BitmapFactory.decodeByteArray(arg0, 0, arg0.length); */

Uri uriTarget = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, new ContentValues());

OutputStream imageFileOS;
try {
imageFileOS = getContentResolver().openOutputStream(uriTarget);
imageFileOS.write(arg0);
imageFileOS.flush();
imageFileOS.close();

Toast.makeText(AndroidCamera.this,
"Image saved: " + uriTarget.toString(),
Toast.LENGTH_LONG).show();

} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

camera.startPreview();
}};

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
if(previewing){
camera.stopPreview();
previewing = false;
}

if (camera != null){
try {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
previewing = true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
camera = Camera.open();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
camera.stopPreview();
camera.release();
camera = null;
previewing = false;
}
}


Download the files.

Related:
- Face detection for Camera



17 comments:

jmiguel rodriguez said...

As this is my first comment in your blog, I must give you a very big THANK YOU! because I'm a beginner trying to make my first android program using camera and your tutorial is teaching me a lot. So, again, THANK YOU!

Well, and now for the real question: in your tutorial, as well as others (including the ApiDemo from google and others), when doing preview over surface I get a distorted image (on a Nexus One, don't know others).

I've been playing with surfaceChanged method trying to get getSupportedPreviewSizes. Also, I found I could try the camera.setDisplayOrientation(degress) method, but could get success.

In all cases, altought preview is broken, the final captured image is fine.

Do you know if there is some standard way to get preview properly displayed.

Thank you very much in advanced.

Erik said...

hello jmiguel.rodriguez,

I don't know what you means "distorted image". As I know there are two problem in my exercise:

i - There is a color-line under the preview, I don't know how to fix it up to now.

ii - The preview rotate 90 degree in some device; it can be: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE).

jmiguel rodriguez said...

Thank you for your reply.

What I mean distorted is this:

http://dl.dropbox.com/u/252834/DSCN0358.JPG

In 'real view' I see it even more distorted. You can check the 90º degrees monitor borders.

Regarding the color line you say, I don't see it, check my photo as is (almost) exactly your sample. I only have change your code to force focus before shot (if you want the code just tell me).

I think my problem comes because width/height ratio is not the same on screen and on final image, but don't know how to solve it. Any idea?

Thank you anyway

Anonymous said...

Hi,
it seems to be interesting ,but i wanna customize my autofocus with sound how could i do that,any ideas
Thanks

Erik said...

hello kamilia,

I don't know if it has any build-in function to play sound when focusing.

But you can Play audio resources using SoundPool.

TouchingTheSky said...

Thank you a million time!!!!
it helped me a lot!!!!

Gwen said...

Thank you very much. You save my night :)

arun said...

Thaaaaaaaaaaaaaaaank you very much...
Really very very very good tutorail.. I learned alot from this tutorial...
Thanks again....

tjr2010 said...

I was trying to copy this code, but I got errors at the @override

NovelX said...

thanks for helping me make my first camera app!

Bill Soriano said...

Hi
Excellent tutorial, thanks for sharing your knowledge, I have a query I add an opaque background and an image on the frame but when I take a photo not recorded

Erik said...

hello Bill Soriano,

The image record from camera, not from your view. I think if you want to add something on the photos, you have to add on the recorded image, not on view/screen.

Bill Soriano said...

good thing ... I will continue investigating

Numair Qadir said...

Hi! Your tutorial is very useful, and i learn alot from it. Thanks alot.
Can you please tell me which type of image format is used in byte[] arg0, and why this is giving a black image when i try to convert via BitmapFactory. What i want is to convert the byte[] image to bitmap. Any help regarding that?

Thank you very much in advance!

Anonymous said...

I am looking to commission an Android Application that measures two things (for benchmarking):
1) Time to autofocus, which includes the steps of running the AF algorithm, by moving the AF mech multiple times, measuring sharpness and going to the position of highest sharpness.
2) Avg time to move the AF mech from mac to inf using 100 measurements.
3) Avg time to move the AF mech from inf to mac using 100 measurements.
I am looking to have this app complete before Christmas.
caubuchon@tessera.com

Anonymous said...

when i run the code, it not opening up the camera..??
why???

Anonymous said...

can u send an application that takes photo and vedio capturing in surface view