我正在尝试制作一个自定义相机应用程序,我想让用户可以在此应用程序中选择对焦模式。
对焦模式是自动和触摸对焦
如果我们想在相机中使用触控对焦,如何入手?
我正在尝试制作一个自定义相机应用程序,我想让用户可以在此应用程序中选择对焦模式。
对焦模式是自动和触摸对焦
如果我们想在相机中使用触控对焦,如何入手?
该功能取决于软件/硬件/制造商,我的建议是你首先找到一个像 Galaxy Nexus 这样的手机刷有 Android 4.x,然后尝试 android.hardware.Camera.Parameters.getMaxNumFocusAreas() ,如果返回值大于零那么你很幸运,然后可以使用 setFocusAreas() 来实现你的“触摸聚焦”功能。
为什么:
在旧的 Android 版本中,没有用于设置焦点区域的公共 API。尽管许多制造商设法创建了自己的 API 和实现,但他们不会分享。
Android 在 API 级别 14 中引入了重点领域 API,但是手机制造商可能会选择不实施(即选择坚持自己的解决方案)。要检查 API 是否受支持,您可以先调用 getMaxNumFocusAreasa(),如果它返回一个正整数,则表示手机确实实现了 API,您可以继续在相机应用中启用“触摸焦点”功能。(API 也是“人脸检测”功能的推动者之一,当人脸被识别时,相机应用程序使用 API 让相机自动对焦于人脸。)
关于如何正确使用 API,您可以参考 vanilla Android Camera 应用程序源代码。
参考:
mInitialParams.getMaxNumFocusAreas()
问候
陈子腾
尝试这个:
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 扫描码一起使用。我相信这同样适用于这样的情况。
它已经实现了,但是如果我想添加触摸到焦点,如何修改它?
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);
}
我试图在我的应用程序中实现焦点功能,并以我想要的方式实现了这个功能。要实现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 上找到示例应用程序- 自定义相机应用程序
调用它来启用触控对焦模式:
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);