前面一篇文章Android Camera基本用法一 只是简单的介绍了Camera的基本用法,很多知识都很粗糙,今天开始一系列文章开始分别学习Camera的知识,这次的内容为Camera对焦。

1 Camera 对焦模式

Camera如果不进行对焦画面会很模糊,Camera的对焦分为自动对焦和触摸对焦,但由于Android各大厂商都可以修改相关源码所以适配存在较多问题。
Camera的对焦模式:

  • FOCUS_MODE_AUTO
    自动对焦模式,应用需要调用autoFocus(AutoFocusCallback)开始对焦,只会对焦一次,对焦成功会有回调。
  • FOCUS_MODE_INFINITY
    无穷对焦模式,应用很少,不能调用autoFocus(AutoFocusCallback)方法。
  • FOCUS_MODE_MACRO
    特写镜头对焦模式,应用需要调用autoFocus(AutoFocusCallback)开始对焦
  • FOCUS_MODE_FIXED
    固定焦点模式,焦点不可调用时都是在这种模式,如果Camera能够自动对焦,这种模式会固定焦点,通常应用于超焦距对焦。这种模式不能调用autoFocus(AutoFocusCallback)。
  • FOCUS_MODE_EDOF
    扩展景深模式,暂时不知道用法。
  • FOCUS_MODE_CONTINUOUS_VIDEO
    连续自动对焦模式,主要用于录制视频过程中,Camera会不断地尝试聚焦,这是录制视频时对焦模式的最好选择,在设置了Camera的参数后就开始自动对焦,但是调用takePicture时不一定已经对焦完成。

从api14开始,这种模式下应用可以调用autoFocus(AutoFocusCallback)进行对焦,焦点回调函数会很快进行回调让我们知道是否对焦成功。这种模式下调用autoFocus后焦点一直是固定的。如果应用想要重新开启自动对焦,需要首先调用cancelAutoFocus。重新开始预览不会重新开启连续自动对焦。

  • FOCUS_MODE_CONTINUOUS_PICTURE
    这种模式是对 FOCUS_MODE_CONTINUOUS_VIDEO连续自动对焦应用于拍照的扩展。Camera会不停的尝试连续对焦,对焦频率会比FOCUS_MODE_CONTINUOUS_VIDEO频繁,当设置了camera参数后开始对焦。

注意如果想要重新开始自动聚焦,需要首先调用cancelAutoFocus,然后设置自动对焦模式,在调用autoFocus(AutoFocusCallback)

if (mCamera != null){mCamera.cancelAutoFocus();mCamera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);mCamera.autoFocus(new Camera.AutoFocusCallback() {@Overridepublic void onAutoFocus(boolean success, Camera camera) {if(success){Toast.makeText(Main22Activity.this,"对焦成功",Toast.LENGTH_SHORT).show();}else{}}});
}

该模式下可调用autoFocus(AutoFocusCallback),如果当前正在对焦扫描,focus回调函数将在它完成对焦是回调;如果没有正在对焦扫描,将立即放回。autoFocus函数调用后对焦区域是固定的,如果应用想要重新开启自动连续对焦,需要首先调用cancelAutoFocus,重新开始预览无法开启自动连续对焦,需要重新调用autoFocus,如果想要停止自动连续对焦,应用可以修改对焦模式。
FOCUS_MODE_AUTO,FOCUS_MODE_CONTINUOUS_VIDEO,FOCUS_MODE_CONTINUOUS_PICTURE通常较为常用。

对焦的意义就是在手机晃动,移动或者改变位置时,拍摄画面依然清晰,如果不进行对焦则画面会很模糊。

示例代码:

public class Main22Activity extends AppCompatActivity implements SurfaceHolder.Callback {private static int mOrientation = 0;private static int mCameraID = Camera.CameraInfo.CAMERA_FACING_BACK;private SurfaceView mSurfaceView;private SurfaceHolder mSurfaceHolder;private Camera mCamera;private boolean havePermission = false;private Button btnFocus;private Button btnTakePic;private Button btnRestar;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main22);btnFocus = findViewById(R.id.focus);btnTakePic = findViewById(R.id.takepic);btnRestar = findViewById(R.id.restar);btnRestar.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(mCamera != null){mCamera.startPreview();}}});btnFocus.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});btnTakePic.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(mCamera!= null){mCamera.takePicture(null, null, new Camera.PictureCallback() {@Overridepublic void onPictureTaken(byte[] data, Camera camera) {// 获取Jpeg图片,并保存在sd卡上String path = Environment.getExternalStorageDirectory().getPath()  +"/focus/";File pathDir = new File(path);if (!pathDir.exists()){pathDir.mkdir();}File pictureFile = new File(path+ "focusdemo.jpg");if (pictureFile.exists()){pictureFile.delete();}try {FileOutputStream fos = new FileOutputStream(pictureFile);fos.write(data);fos.close();} catch (Exception e) {}}});}}});// Android 6.0相机动态权限检查,省略了if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)== PackageManager.PERMISSION_GRANTED &&ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED) {havePermission = true;init();} else {havePermission = false;ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);}}public void init(){if(mSurfaceView == null){mSurfaceView = findViewById(R.id.surfaceview);mSurfaceView.setCustomEvent(new CustomSurfaceView.ONTouchEvent() {@Overridepublic void onTouchEvent(MotionEvent event) {handleFocus(event, mCamera);}});mSurfaceHolder = mSurfaceView.getHolder();mSurfaceHolder.addCallback(this);WindowManager wm = (WindowManager) Main23Activity.this.getSystemService(Context.WINDOW_SERVICE);int width = wm.getDefaultDisplay().getWidth();LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) mSurfaceView.getLayoutParams();layoutParams.width = width;layoutParams.height = width*4/3;useWidth = width;useHeight = width*4/3;mSurfaceView.setLayoutParams(layoutParams);}}private void initCamera() {if (mCamera != null){releaseCamera();System.out.println("===================releaseCamera=============");}mCamera = Camera.open(mCameraID);System.out.println("===================openCamera=============");if (mCamera != null){try {mCamera.setPreviewDisplay(mSurfaceHolder);} catch (IOException e) {e.printStackTrace();}Camera.Parameters parameters = mCamera.getParameters();parameters.setRecordingHint(true);{//设置获取数据parameters.setPreviewFormat(ImageFormat.NV21);//parameters.setPreviewFormat(ImageFormat.YUV_420_888);//通过setPreviewCallback方法监听预览的回调:mCamera.setPreviewCallback(new Camera.PreviewCallback() {@Overridepublic void onPreviewFrame(byte[] bytes, Camera camera) {//这里面的Bytes的数据就是NV21格式的数据,或者YUV_420_888的数据}});}if(mCameraID == Camera.CameraInfo.CAMERA_FACING_BACK){parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);}mCamera.setParameters(parameters);calculateCameraPreviewOrientation(this);Camera.Size tempSize = setPreviewSize(mCamera, useHeight,useWidth);{//此处可以处理,获取到tempSize,如果tempSize和设置的SurfaceView的宽高冲突,重新设置SurfaceView的宽高}setPictureSize(mCamera,  useHeight,useWidth);mCamera.setDisplayOrientation(mOrientation);int degree = calculateCameraPreviewOrientation(Main23Activity.this);mCamera.setDisplayOrientation(degree);mCamera.startPreview();}}public void releaseCamera(){if (mCamera != null) {mSurfaceHolder.removeCallback(this);mCamera.setPreviewCallback(null);mCamera.stopPreview();mCamera.lock();mCamera.release();mCamera = null;}}@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {//当SurfaceView变化时也需要做相应操作,这里未做相应操作if (havePermission){initCamera();}}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mCamera.stopPreview();}private void setPictureSize(Camera camera ,int expectWidth,int expectHeight){Camera.Parameters parameters = camera.getParameters();Point point = new Point(expectWidth, expectHeight);Camera.Size size = findProperSize(point,parameters.getSupportedPreviewSizes());parameters.setPictureSize(size.width, size.height);camera.setParameters(parameters);}private Camera.Size setPreviewSize(Camera camera, int expectWidth, int expectHeight) {Camera.Parameters parameters = camera.getParameters();Point point = new Point(expectWidth, expectHeight);Camera.Size size = findProperSize(point,parameters.getSupportedPictureSizes());parameters.setPictureSize(size.width, size.height);camera.setParameters(parameters);return size;}/*** 找出最合适的尺寸,规则如下:* 1.将尺寸按比例分组,找出比例最接近屏幕比例的尺寸组* 2.在比例最接近的尺寸组中找出最接近屏幕尺寸且大于屏幕尺寸的尺寸* 3.如果没有找到,则忽略2中第二个条件再找一遍,应该是最合适的尺寸了*/private static Camera.Size findProperSize(Point surfaceSize, List<Camera.Size> sizeList) {if (surfaceSize.x <= 0 || surfaceSize.y <= 0 || sizeList == null) {return null;}int surfaceWidth = surfaceSize.x;int surfaceHeight = surfaceSize.y;List<List<Camera.Size>> ratioListList = new ArrayList<>();for (Camera.Size size : sizeList) {addRatioList(ratioListList, size);}final float surfaceRatio = (float) surfaceWidth / surfaceHeight;List<Camera.Size> bestRatioList = null;float ratioDiff = Float.MAX_VALUE;for (List<Camera.Size> ratioList : ratioListList) {float ratio = (float) ratioList.get(0).width / ratioList.get(0).height;float newRatioDiff = Math.abs(ratio - surfaceRatio);if (newRatioDiff < ratioDiff) {bestRatioList = ratioList;ratioDiff = newRatioDiff;}}Camera.Size bestSize = null;int diff = Integer.MAX_VALUE;assert bestRatioList != null;for (Camera.Size size : bestRatioList) {int newDiff = Math.abs(size.width - surfaceWidth) + Math.abs(size.height - surfaceHeight);if (size.height >= surfaceHeight && newDiff < diff) {bestSize = size;diff = newDiff;}}if (bestSize != null) {return bestSize;}diff = Integer.MAX_VALUE;for (Camera.Size size : bestRatioList) {int newDiff = Math.abs(size.width - surfaceWidth) + Math.abs(size.height - surfaceHeight);if (newDiff < diff) {bestSize = size;diff = newDiff;}}return bestSize;}private static void addRatioList(List<List<Camera.Size>> ratioListList, Camera.Size size) {float ratio = (float) size.width / size.height;for (List<Camera.Size> ratioList : ratioListList) {float mine = (float) ratioList.get(0).width / ratioList.get(0).height;if (ratio == mine) {ratioList.add(size);return;}}List<Camera.Size> ratioList = new ArrayList<>();ratioList.add(size);ratioListList.add(ratioList);}/*** 排序* @param list*/private static void sortList(List<Camera.Size> list) {Collections.sort(list, new Comparator<Camera.Size>() {@Overridepublic int compare(Camera.Size pre, Camera.Size after) {if (pre.width > after.width) {return 1;} else if (pre.width < after.width) {return -1;}return 0;}});}/*** 设置预览角度,setDisplayOrientation本身只能改变预览的角度* previewFrameCallback以及拍摄出来的照片是不会发生改变的,拍摄出来的照片角度依旧不正常的* 拍摄的照片需要自行处理* 这里Nexus5X的相机简直没法吐槽,后置摄像头倒置了,切换摄像头之后就出现问题了。* @param activity*/public static int calculateCameraPreviewOrientation(Activity activity) {Camera.CameraInfo info = new Camera.CameraInfo();Camera.getCameraInfo(mCameraID, info);int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();int degrees = 0;switch (rotation) {case Surface.ROTATION_0:degrees = 0;break;case Surface.ROTATION_90:degrees = 90;break;case Surface.ROTATION_180:degrees = 180;break;case Surface.ROTATION_270:degrees = 270;break;}int result;if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {result = (info.orientation + degrees) % 360;result = (360 - result) % 360;} else {result = (info.orientation - degrees + 360) % 360;}mOrientation = result;System.out.println("=========orienttaion============="+result);return result;}@Overrideprotected void onResume() {super.onResume();if (havePermission && mCamera != null)mCamera.startPreview();}@Overrideprotected void onPause() {super.onPause();if (havePermission && mCamera != null)mCamera.stopPreview();}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);switch (requestCode) {// 相机权限case 100:havePermission = true;init();break;}}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><SurfaceViewandroid:id="@+id/surfaceview"android:layout_width="wrap_content"android:layout_height="wrap_content" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:id="@+id/focus"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="focus"/><Buttonandroid:id="@+id/takepic"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="takePic"/><Buttonandroid:id="@+id/restar"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="restar"/></LinearLayout>

可以看到改变距离时画面会变得很模糊。

2各种对焦模式的自动对焦应用

统一说明:由于采用竖屏拍摄照片,保存的照片和底层传感器方向一致还是横屏的,没有对保存的数据进行旋转,所以拍出的照片被旋转了,后面会开文章对前置后置摄像头拍出的照片进行处理。

FOCUS_MODE_AUTO 自动对焦

parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
设置这种模式之后,很多手机不会自动对焦,还是需要手动调用autoFocus函数才会对焦。

btnFocus.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (mCamera != null){mCamera.autoFocus(new Camera.AutoFocusCallback() {@Overridepublic void onAutoFocus(boolean success, Camera camera) {if(success){Toast.makeText(Main22Activity.this,"对焦成功",Toast.LENGTH_SHORT).show();}else{}}});}}
});

这种模式很多手机上无法实现自动对焦,改变手机位置或者拍照之前需要调用autoFocus进行对焦,效果一般。拍照之前进行对焦,对焦成功进行拍照。

FOCUS_MODE_CONTINUOUS_VIDEO

parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
这种模式可以实现自动对焦,但据网上大家反映对焦时会连续闪动。

FOCUS_MODE_CONTINUOUS_PICTURE

parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);

大部分手机在这种模式下会自动对焦,网上说有部分手机不会自动对焦。

3手动对焦(触摸对焦)

前面讲解了可以设置自动对焦模式,然后每次需要手动调用autoFocus函数进行对焦,此外Camera还提供了一种手动对焦模式叫做触摸对焦。
触摸对焦,就是在屏幕上点击某个点,通过setFocusAreas()指定这个对焦区域,应用到相机,相机就以此点内容进行对焦,保证此点最清晰。
利用setFocusAreas函数 ,在api14添加,api14之前只能调用autoFocus函数进行,研究setFocusAreas时官方文档指引我们看getFocusAreas()的说明。

setFocusAreas(List focusAreas)
只在FOCUS_MODE_AUTO,FOCUS_MODE_CONTINUOUS_VIDEO,FOCUS_MODE_CONTINUOUS_PICTURE这三种模式下有效。

要使用setFocusAreas首先要判断是否支持设置定点对焦,api14以下是不支持的,另外还需要判断getMaxNumFocusAreas()的值,如果小于等于0也是不支持定点对焦的。
目前市场大部分手机这个方法的返回值,前置摄像头都是0,后置摄像头都是1,说明前置摄像头一般不支持设置聚焦,而后置摄像头一般也只支持单个区域的聚焦。

Area类用于标识感光区域(测光)和聚焦区域,用于相机计算自动曝光、自动白平衡、自动聚焦。每一个Area是一个矩形区域,有一个weight标识它的重要程度。Camera的可以设置定点对焦的区域会被映射到一个左上角为(-1000,-1000)到右下角(1000,1000)的区域上。在这个范围之外设置无效,如果area的大小为0或者weight为负是不被允许的。
Camera.Area对象,包含两个参数:
Rect对象,它用于指定Camera预览窗口一块矩形区域(测光区域)
一个权重值(weight),它告诉Camera这块指定区域应该给予的测光或调焦计算的重要性等级,权重大的优先级高,权重最高为1000

Weight的取值范围必须是(1,1000),weight值越大,当我们添加多个聚焦区域时,weight大的区域起到的作用越大。

如何把Camera坐标映射到(-1000,-1000)到(1000,1000)坐标上。

/*** 转换对焦区域* 范围(-1000, -1000, 1000, 1000)
* x,y是坐标位置,width,height SurfaceView的宽高,coefficient是区域比例大小*/
private  Rect calculateTapArea(float x, float y,  int width, int height, float coefficient) {float focusAreaSize = 200;//这段代码可以看出coefficient的作用,只是为了扩展areaSize。int areaSize = (int) (focusAreaSize * coefficient);int surfaceWidth = width;int surfaceHeight = height;//解释一下为什么*2000,因为要把surfaceView的坐标转换为范围(-1000, -1000, 1000, 1000),则SurfaceView的中心点坐标会转化为(0,0),x/surfaceWidth ,得到当前x坐标占总宽度的比例,然后乘以2000就换算成了(0,0,2000,2000)的坐标范围内,然后减去1000,就换算为了范围(-1000, -1000, 1000, 1000)的坐标。//得到了x,y转换后的坐标,利用areaSize就可以得到聚焦区域。int centerX = (int) (x / surfaceHeight * 2000 - 1000);int centerY = (int) (y / surfaceWidth * 2000 - 1000);int left = clamp(centerX - (areaSize / 2), -1000, 1000);int top = clamp(centerY - (areaSize / 2), -1000, 1000);int right = clamp(left + areaSize, -1000, 1000);int bottom = clamp(top + areaSize, -1000, 1000);return new Rect(left, top, right, bottom);
}
//不大于最大值,不小于最小值
private  int clamp(int x, int min, int max) {if (x > max) {return max;}if (x < min) {return min;}return x;
}

在得到转换后的矩形后就可以直接通过setFocusAreas()应用到相机了?实际没这么简单。直接这么做往往不能达到理想的效果,因为Android本身的问题以及设备的差异,在常用的对焦模式为continuous-picture下,setFocusAreas()可能会不工作。目前常用的解决办法是在setFocusAreas()同时修改相机对焦模式为macro等,待对焦完毕后,再将对焦模式修改为用户之前定义的。

使用实例:

public class CustomSurfaceView extends SurfaceView {private ONTouchEvent mTouchEvent;public CustomSurfaceView(Context context) {super(context);}public CustomSurfaceView(Context context, AttributeSet attrs) {super(context, attrs);}public CustomSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (MotionEvent.ACTION_DOWN == event.getAction()){mTouchEvent.onTouchEvent(event);}return super.onTouchEvent(event);}public void setCustomEvent(ONTouchEvent onTouchEvent){mTouchEvent = onTouchEvent;}public interface ONTouchEvent{public void  onTouchEvent(MotionEvent event);}
}mSurfaceView.setCustomEvent(new CustomSurfaceView.ONTouchEvent() {@Overridepublic void onTouchEvent(MotionEvent event) {handleFocus(event, mCamera);}
});private  void handleFocus(MotionEvent event, Camera camera) {int viewWidth = useWidth;int viewHeight = useHeight;Rect focusRect = calculateTapArea(event.getX(), event.getY(),  viewWidth, viewHeight,1.0f);//一定要首先取消,否则无法再次开启camera.cancelAutoFocus();Camera.Parameters params = camera.getParameters();if (params.getMaxNumFocusAreas() > 0) {List<Camera.Area> focusAreas = new ArrayList<>();focusAreas.add(new Camera.Area(focusRect, 800));params.setFocusAreas(focusAreas);} else {//focus areas not supported}//首先保存原来的对焦模式,然后设置为macro,对焦回调后设置为保存的对焦模式final String currentFocusMode = params.getFocusMode();params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);camera.setParameters(params);camera.autoFocus(new Camera.AutoFocusCallback() {@Overridepublic void onAutoFocus(boolean success, Camera camera) {//回调后 还原模式Camera.Parameters params = camera.getParameters();params.setFocusMode(currentFocusMode);camera.setParameters(params);if(success){Toast.makeText(Main22Activity.this,"对焦区域对焦成功",Toast.LENGTH_SHORT).show();}}});
}

可以看到视频中有远近不同的两个物品,当近处物品清晰时远处不清晰,当远处物品清晰时近处不清晰,点击不同区域对焦area变换,可以转换近处和远处,如下图:

没有远近物品时:

触摸测光

还有一种增强Camera的方式叫做触摸测光,就是在屏幕上点击某个点,相机调整曝光亮度,保证此点亮度最为合适;

setMeteringAreas设置感光区域,也是利用Area设置测光的区域,使用之前要先调用getMaxNumMeteringAreas如果大于0说明支持测光,否则不支持无法使用。

触摸测光与触摸对焦类似,只是作用稍有不同,触摸对焦用于改变聚焦点,触摸测光用于改变光的强弱,一般两者结合使用。
注意:有时可能因为设置的区域过小或者权重weight过小导致效果不明显可以增大区域和weight。

5 如何实现自动对焦

上面说了利用对焦模式实现自动对焦会存在有的手机不支持的情况,所以要实现自动对焦还得利用触摸对焦的方式实现。
最通用的做法就是通过监听加速度传感器的变化,传感器数值改变超过了一定范围时调用对焦函数自动对焦。
简单实例:

@Override
public void onSensorChanged(SensorEvent event) {//手机移动一段时间后静止,然后静止一段时间后进行对焦// 读取加速度传感器数值,values数组0,1,2分别对应x,y,z轴的加速度if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {int x = (int) event.values[0];int y = (int) event.values[1];int z = (int) event.values[2];//如果满足条件调用触摸对焦方法。
//具体实现参考:https://github.com/WellerV/SweetCamera}
}SweetCamera 实现方式:
/*
稍微解释一下SweetCamera的处理传感器的思路,通过传感器数据记录移动点和静止点,如果上一次是移动状态,现在是静止状态,且静止持续了一定时间就可以调用对焦函数进行对焦。
*/if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {int x = (int) event.values[0];int y = (int) event.values[1];int z = (int) event.values[2];mCalendar = Calendar.getInstance();long stamp = mCalendar.getTimeInMillis();int second = mCalendar.get(Calendar.SECOND);if (STATUE != STATUS_NONE) {int px = Math.abs(mX - x);int py = Math.abs(mY - y);int pz = Math.abs(mZ - z);double value = Math.sqrt(px * px + py * py + pz * pz);if (value > 1.4) {STATUE = STATUS_MOVE;} else {//上一次状态是move,记录静态时间点if (STATUE == STATUS_MOVE) {lastStaticStamp = stamp;canFocusIn = true;}if (canFocusIn) {if (stamp - lastStaticStamp > DELEY_DURATION) {//移动后静止一段时间,可以发生对焦行为if (!isFocusing) {canFocusIn = false;if (mCameraFocusListener != null) {mCameraFocusListener.onFocus();}}}}STATUE = STATUS_STATIC;}} else {lastStaticStamp = stamp;STATUE = STATUS_STATIC;}mX = x;mY = y;mZ = z;}

PS:由于手头没有太多手机,没有进行机型适配,听说魅族的会问题多一点,以上gif图有点模糊是音频,利用screenrecorder命令进行录制只能录制为mp4,之后又利用gif软件录制的MP4视频,所以画面比较模糊。

Android Camera对焦相关基础自动对焦,手动对焦相关推荐

  1. Android camera(4)---Android Camera开发之基础知识篇

    Android Camera开发之基础知识篇 转自:https://blog.csdn.net/feiduclear_up/article/details/51968975#jump5 概述 Andr ...

  2. android Camera自动拍照、自动对焦并获取指定大小图片

    1.首先android6.0以上版本要动态申请相机和文件读写权限 2.废话不啰嗦,上代码: /*** 摄像头画面采集界面*/ public class DistinguishActivity exte ...

  3. Android IPC机制之IPC概念、Android 多进程和相关基础知识

    1.IPC 的基本概念 1.1 IPC的使用场景 IPC 即 Inter-Process Communication 进程间通信,IPC用于多进程,而Android的多进程情况一般有: 1.一个应用需 ...

  4. android camera 对焦大小,Android camera2对焦设置

    在android camera2 api 开始,提供了对焦距值(非zoom值)的设置,大概步骤如下: (1)先关闭自动焦距模式    mPreviewBuilder.set(CaptureReques ...

  5. Android Camera驱动相关参数学习

    https://www.freesion.com/article/4029747962/ https://wenku.baidu.com/view/d335e7da647d27284a7351b7.h ...

  6. 一牛网:Android camera驱动培训班,不可错过的学习机会

    Android camera驱动培训: 学员要求: 1.要有C语言基础 2.有android.linux.或其他嵌入式系统基础 3.对这块有强烈兴趣者. 师资团队: 主讲:一牛网_Jacky 老师(驱 ...

  7. Android camera 相关术语(四) 之  变焦和对焦的区别VCM 闭环和开环在硬件上有什么区别

    Android camera 相关术语(四) 之  变焦和对焦的区别VCM 闭环和开环在硬件上有什么区别 VCM 闭环马达(即close loop)与开环马达(即open loop)一般有两个硬件上的 ...

  8. camera(17)---设置摄像头方向、打开线程与预览线程、设置参数、Camera外设按键、自动对焦与触摸对焦、拍照、人脸检测、位置管理、旋转管理、变焦、录像

    [Android]设置摄像头方向.打开线程与预览线程.设置参数.Camera外设按键.自动对焦与触摸对焦.拍照.人脸检测.位置管理.旋转管理.变焦.录像 阅读数:1673 设置摄像头方向.打开线程与预 ...

  9. android camera 显示过程,Android相机Camera基础知识

    一.概述本章节主要讲述的Android相机Camera的相关知识点,主要包含三个方面,Android启动系统相机生成缩略图.Android启动系统相机生成原图以及Android自定义相机等. 二.An ...

  10. Android Camera开发(一)之基础知识

    概述 Android手机关于Camera的使用,一是拍照,二是摄像,由于Android提供了强大的组件功能,为此对于在Android手机系统上进行Camera的开发,我们可以使用两类方法:一是借助In ...

最新文章

  1. Openfiler之一:Openfiler的安装
  2. Android 调试 Release 包(debuggable)
  3. 使用C#格式化字符串
  4. 钉钉微应用的开发——主前端
  5. C++面向对象设计原则详解
  6. Google Guava –期货
  7. 前端学习(1676):前端系列实战课程之贪吃蛇游戏设计
  8. Java笔记-Spring Boot JDBC连接Oracle数据库
  9. Exchange Server 2013系列四:小企业邮件系统部署
  10. 子列和列_最大子列和 - fanlinglong - 博客园
  11. Android现学现用第十一天
  12. tsmsbs项目中用到的触发器和存储过程
  13. pythonATM,购物车项目实战5-数据处理层
  14. 基于sklearn框架实现线性回归,多项式回归和支持向量机的项目实战
  15. mybatis 插件
  16. Mobile-Former: Bridging MobileNet and Transformer详解
  17. 暗月渗透实战靶场-项目七(下)
  18. H3C交换机基本命令
  19. K8S集群中Pod资源处于Terminating或Unknown状态排查思路
  20. 如何删除流氓软件?流氓软件删除后还是自动安装怎么办?

热门文章

  1. 有了域名和服务器怎么创建网站,怎么建立网站,如何创建网站,有哪些步骤?...
  2. c语言投票系统程序,C语言智能投票系统.doc
  3. nodejs+mp2+mbtiles+实现google底图服务(centos7)
  4. MDK各芯片厂家安装支持包下载地址(含Stm32,Nuvoton等)
  5. msl3等级烘烤时间_MSL(湿气敏感性等级)
  6. Unity 读取本地文件夹图片
  7. 将文件夹中的图片批量分割
  8. 【ZZULIOJ】1092: 素数表(函数专题)
  9. FISCO BCOS区块链搭建说明(第一篇)
  10. ld cannot find -lbz2