Android相机对焦模式

我正在尝试制作一个自定义相机应用程序,我想让用户可以在此应用程序中select对焦模式。

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

如果我们想在相机中使用触摸对焦,可以从哪里开始呢?

Solutions Collecting From Web of "Android相机对焦模式"

尝试这个:

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扫描代码。 我相信同样的情况也适用于这样的情况。

该function是软件/硬件/制造依赖,我的build议是,你首先find一个像Galaxy Nexus闪存与Android 4.x的手机,然后尝试android.hardware.Camera.Parameters.getMaxNumFocusAreas()就可以了,如果返回值大于零,那么你很幸运,然后可以使用setFocusAreas()来实现你的“触摸对焦”function。

为什么:

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

Android在API级别14中引入了重点领域API,但是电话制造商可能select不实施(即select坚持自己的解决scheme)。 要检查API是否受支持,可以先调用getMaxNumFocusAreasa(),如果它返回一个正整数,这意味着手机实现了API,并且可以继续在相机应用程序中启用“触摸焦点”function。 (API也是“脸部检测”function的推动者之一,当识别到脸部时,相机应用使用API​​让相机自动对焦。)

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

参考文献:

  1. Android相机API

getMaxNumFocusAreas()

setFocusAreas()

  1. Android 4.0相机应用程序源代码

mInitialParams.getMaxNumFocusAreas()

mParameters.setFocusAreas()

问候

陈子田

它已经实施,但如果我想添加触摸来关注如何修改这个?

 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); } 

我试图在我的应用程序中实现焦点function,并以我想要的方式实现了这个function。 要实现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上find示例应用程序

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

 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);