Android相机对焦模式

时间:2012-07-27 04:00:41

标签: android android-intent focus byte android-camera

我正在尝试制作自定义相机应用程序 我想让用户可以在此应用程序中选择焦点模式。

对焦模式为自动和触摸对焦

如果我们想在相机中使用触摸式对焦,那么如何开始?

5 个答案:

答案 0 :(得分:16)

该功能取决于软件/硬件/制造商,我的建议是你首先找到像Android 4.x一样用Galaxy Nexus闪存的手机,然后在其上试用android.hardware.Camera.Parameters.getMaxNumFocusAreas(),如果返回值大于零然后你很幸运,然后可以使用setFocusAreas()来实现“触摸聚焦”功能。

为什么:

在旧的Android版本中,没有公共API来设置焦点区域。虽然许多制造商设法创建自己的API和实现,但他们不会分享。

Android在API级别14中引入了重点领域API,但手机制造商可能会选择不实施它(即选择坚持自己的解决方案)。要检查API是否受支持,您可以先调用getMaxNumFocusAreasa(),如果它返回一个正整数,表示手机确实实现了API,您可以继续在相机应用程序中启用“触摸焦点”功能。 (API也是“面部检测”功能的推动者之一,当识别出面部时,相机应用程序使用API​​让相机自动对焦于它们。)

您可以参考vanilla Android Camera应用程序源代码,了解如何正确使用API​​。

参考文献:

  1. Android Camera API
  2. getMaxNumFocusAreas()

    setFocusAreas()

    1. Android 4.0相机应用源代码
    2. mInitialParams.getMaxNumFocusAreas()

      mParameters.setFocusAreas()

      此致

      陈子腾

答案 1 :(得分:8)

试试这个:

public void takePhoto(File photoFile, String workerName, int width, int height, int    quality) {
if (getAutoFocusStatus()){
    camera.autoFocus(new AutoFocusCallback() {
        @Override
        public void onAutoFocus(boolean success, Camera camera) {
            camera.takePicture(shutterCallback, rawCallback, jpegCallback);
        }
    }); 
}else{
    camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}

但是,我也看到了这种方法,可能更准确:

if (getAutoFocusStatus()){
    camera.autoFocus(new AutoFocusCallback() {
        @Override
        public void onAutoFocus(boolean success, Camera camera) {
           if(success) camera.takePicture(shutterCallback, rawCallback, jpegCallback);
        }
    }); 
}else{
    camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}

最后一张照片是在聚焦成功完成时拍摄的。它适用于QR扫描码。我认为这同样适用于这种情况。

答案 2 :(得分:5)

如果我想添加触摸来进行聚焦,它已经实现但是如何修改它?

public void takePhoto(File photoFile, String workerName, int width, int height, int    quality) {
    if (getAutoFocusStatus()){
        camera.autoFocus(new AutoFocusCallback() {
            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                camera.takePicture(shutterCallback, rawCallback, jpegCallback);
            }
        }); 
    }else{
        camera.takePicture(shutterCallback, rawCallback, jpegCallback);
    }

    this.photoFile = photoFile;
    this.workerName = workerName;
    this.imageOutputWidth = width;
    this.imageOutputHeight = height;
}

public void takePhoto(File photoFile, int width, int height, int quality) {
    takePhoto(photoFile, null, width, height, quality);
}

答案 3 :(得分:2)

我试图在我的应用中实现焦点功能,并以我想要的方式实现此功能。要实施Touch to Focus,请参阅以下代码。

CameraPreview.java

public class CameraPreview extends SurfaceView implements
    SurfaceHolder.Callback {
private SurfaceHolder mSurfaceHolder;
private Camera mCamera;
private OnFocusListener onFocusListener;

private boolean needToTakePic = false;

private Camera.AutoFocusCallback myAutoFocusCallback = new Camera.AutoFocusCallback() {

    @Override
    public void onAutoFocus(boolean arg0, Camera arg1) {
        if (arg0) {
            mCamera.cancelAutoFocus();
        }
    }
};

// Constructor that obtains context and camera
@SuppressWarnings("deprecation")
public CameraPreview(Context context, Camera camera) {
    super(context);
    this.mCamera = camera;
    this.mSurfaceHolder = this.getHolder();
    this.mSurfaceHolder.addCallback(this);
    this.mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    this.onFocusListener = (OnFocusListener) context;
}

@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
    try {
        mCamera.setPreviewDisplay(surfaceHolder);
        mCamera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        mCamera.setDisplayOrientation(90);
        mCamera.startPreview();
    } catch (IOException e) {
        // left blank for now
        e.printStackTrace();
    }
}

@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
    mCamera.stopPreview();
    this.mSurfaceHolder.removeCallback(this);
    mCamera.release();
}

@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format,
                           int width, int height) {
    // start preview with new settings
    try {
        mCamera.setPreviewDisplay(surfaceHolder);
        mCamera.startPreview();
    } catch (Exception e) {
        // intentionally left blank for a test
        e.printStackTrace();
    }
}

/**
 * Called from PreviewSurfaceView to set touch focus.
 *
 * @param - Rect - new area for auto focus
 */
public void doTouchFocus(final Rect tfocusRect) {
    try {
        List<Camera.Area> focusList = new ArrayList<Camera.Area>();
        Camera.Area focusArea = new Camera.Area(tfocusRect, 1000);
        focusList.add(focusArea);

        Camera.Parameters param = mCamera.getParameters();
        param.setFocusAreas(focusList);
        param.setMeteringAreas(focusList);
        mCamera.setParameters(param);

        mCamera.autoFocus(myAutoFocusCallback);
    } catch (Exception e) {
        e.printStackTrace();
    }

    if (isNeedToTakePic()) {
        onFocusListener.onFocused();
    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {

    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        float x = event.getX();
        float y = event.getY();

        Rect touchRect = new Rect(
                (int) (x - 100),
                (int) (y - 100),
                (int) (x + 100),
                (int) (y + 100));


        final Rect targetFocusRect = new Rect(
                touchRect.left * 2000 / this.getWidth() - 1000,
                touchRect.top * 2000 / this.getHeight() - 1000,
                touchRect.right * 2000 / this.getWidth() - 1000,
                touchRect.bottom * 2000 / this.getHeight() - 1000);

        doTouchFocus(targetFocusRect);
    }

    return false;
}

public boolean isNeedToTakePic() {
    return needToTakePic;
}

public void setNeedToTakePic(boolean needToTakePic) {
    this.needToTakePic = needToTakePic;
}
}

MainActivity.java

public class MainActivity extends Activity
    implements OnFocusListener {
private Button captureButton, switchCameraButton;
private Camera mCamera;
private CameraPreview mCameraPreview;
private int currentCameraId;

/**
 * Called when the activity is first created.
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (getIntent().hasExtra("camera_id")) {
        currentCameraId = getIntent().getIntExtra("camera_id", Camera.CameraInfo.CAMERA_FACING_BACK);
    } else {
        currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
    }

    captureButton = (Button) findViewById(R.id.button_capture);
    captureButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(final View v) {
            // Obtain MotionEvent object
            v.setEnabled(false);
            mCameraPreview.setNeedToTakePic(true);
            long downTime = SystemClock.uptimeMillis();
            long eventTime = SystemClock.uptimeMillis() + 100;
            float x = mCameraPreview.getWidth() / 2;
            float y = mCameraPreview.getHeight() / 2;
            // List of meta states found here:     developer.android.com/reference/android/view/KeyEvent.html#getMetaState()
            int metaState = 0;
            MotionEvent motionEvent = MotionEvent.obtain(
                    downTime,
                    eventTime,
                    MotionEvent.ACTION_DOWN,
                    x,
                    y,
                    metaState
            );

            // Dispatch touch event to view
            mCameraPreview.dispatchTouchEvent(motionEvent);
        }
    });

    switchCameraButton = (Button) findViewById(R.id.button_switch_camera);
    switchCameraButton.setVisibility(
            Camera.getNumberOfCameras() > 1 ? View.VISIBLE : View.GONE);
    switchCameraButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mCamera.stopPreview();
            //NB: if you don't release the current camera before switching, you app will crash
            mCameraPreview.getHolder().removeCallback(mCameraPreview);
            mCamera.release();

            //swap the id of the camera to be used
            if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
                currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
            } else {
                currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
            }

            mCamera = getCameraInstance(currentCameraId);
            mCameraPreview = new CameraPreview(MainActivity.this, mCamera);
            FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
            preview.removeAllViews();
            preview.addView(mCameraPreview);
        }
    });
}

@Override
protected void onResume() {
    super.onResume();
    mCamera = getCameraInstance(currentCameraId);
    mCameraPreview = new CameraPreview(this, mCamera);
    FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    preview.addView(mCameraPreview);
}

/**
 * Helper method to access the camera returns null if it cannot get the
 * camera or does not exist
 *
 * @return
 */
private Camera getCameraInstance(int currentCameraId) {
    Camera camera = null;
    try {
        camera = Camera.open(currentCameraId);
    } catch (Exception e) {
        // cannot get camera or does not exist
    }
    return camera;
}

Camera.PictureCallback mPicture = new Camera.PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        File pictureFile = getOutputMediaFile();
        if (pictureFile == null) {
            return;
        }
        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
};

private static File getOutputMediaFile() {
    File mediaStorageDir = new File(
            Environment
                    .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            "MyCameraApp");
    if (!mediaStorageDir.exists()) {
        if (!mediaStorageDir.mkdirs()) {
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }
    // Create a media file name
    //        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
    //                .format(new Date());
    File mediaFile;
    mediaFile = new File(mediaStorageDir.getPath() + File.separator
            + "IMG_" + "DEMO_" + ".jpg");
    if (mediaFile.exists()) mediaFile.delete();

    return mediaFile;
}

@Override
public void onFocused() {
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            mCamera.takePicture(null, null, mPicture);
            mCameraPreview.setNeedToTakePic(false);
            captureButton.setEnabled(true);
        }
    }, 1500);
}
}

activity_main.xml中

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">

<FrameLayout
    android:id="@+id/camera_preview"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_weight="1" />

<Button
    android:id="@+id/button_switch_camera"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="Switch Camera" />

<Button
    android:id="@+id/button_capture"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="Capture" />

</LinearLayout>

您可以在Github - Custom Camera App

上找到示例应用

答案 4 :(得分:0)

调用此选项以启用触摸对焦模式:

private void setTouchToFocusMode(Camera.Parameters parameters){
    String focusMode;
    if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
        focusMode = Camera.Parameters.FOCUS_MODE_AUTO;
    }
    if (focusMode != null && focusMode.length() > 0){
        parameters.setFocusMode(focusMode);
    }
}

当用户点击屏幕时,请在下面调用以设置焦点区域:

private static final int FOCUS_WIDTH = 80;
private static final int FOCUS_HEIGHT = 80;

public static String setFocalPoint(Camera.Parameters params, int x, int y){
    String focusMode = "";
    if (params != null && params.getMaxNumFocusAreas() > 0) {
        List<Camera.Area> focusArea = new ArrayList<Camera.Area>();
        focusArea.add(new Camera.Area(new Rect(x, y, x + FOCUS_WIDTH, y + FOCUS_HEIGHT), 1000));

        params.setFocusAreas(focusArea);

        if(params.getMaxNumMeteringAreas() > 0) {
            params.setMeteringAreas(focusArea);
        }
        if(params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            focusMode = Camera.Parameters.FOCUS_MODE_AUTO;
        }
    }
    return focusMode;
}

调用autoFocus / cancelAutoFocus进行操作:

mCamera.cancelAutoFocus();    
mCamera.autoFocus(mAutoFocusCallback);