最近在学习有关人脸识别的闸机系统,对用到的知识点进行总结.
Android5.0后就弃用了Camera1,而Camera1和Camera2的差别还是很大的,Camera2提供了很多新特性.本文使用Camera2实现了相机预览,拍照等功能.
开发工具:AS 3.4.1 真机:荣耀10
以下是部分重要代码,文章最后附有完整的Demo地址.
主要的api:
1.CameraManager:摄像头管理者,用于检测、描述和连接到照相机设备;
2.CameraCharacteristics:摄像头的属性信息,可以获取摄像头的FPS,支持尺寸等属性;
3.CameraDevice:表示摄像头设备;
4.CameraCaptureSession:相机捕捉会话,通过setRepeatingRequest不断请求捕捉图像;
5.ImageReader.OnImageAvailableListener中的onImageAvailable:获取预览的图像数据,可进行转化,保存图像等操作.
主要流程:
1.使用TextureView作为载体展示预览内容,
2.动态申请权限,权限通过后进行视图的初始化,遍历摄像头,创建工作线程,以及监听SurfaceTexture的状态;
这里的匿名内部类用到了jdk8的新特性Lambda表达式(后面写个关于Lambda的博客)
权限模板可参考我另一边博客:https://blog.csdn.net/sunyFS/article/details/98175130
//java 1.8的Lambda表达式
setPermissions(mPermissions, () -> {
Toast.makeText(MainActivity.this, "权限已全部允许,可进行初始化操作", Toast.LENGTH_SHORT).show();
initView();
initLooper();
});
}
private void initView() {
btn_switch = findViewById(R.id.btn_switch);
ttvPreview = findViewById(R.id.ttvPreview);
btn_switch.setOnClickListener(this);
//遍历摄像头,检查摄像头是否可用,以及获取摄像头支持的尺寸,FPS等属性
cameraList();
//监听SurfaceTexture状态,SurfaceTexture可用时回调onSurfaceTextureAvailable方法
ttvPreview.setSurfaceTextureListener(this);
}
private void initLooper() {
//创建HandlerThread,用"CAMERA2"标记
mThreadHandler = new HandlerThread("CAMERA2");
//启动线程
mThreadHandler.start();
//创建工作线程Handler
mHandler = new Handler(mThreadHandler.getLooper());
}
3.遍历摄像头cameraList(),这里我默认使用后置摄像头mCameraId = mBackCameraId;
通过getSystemService(Context.CAMERA_SERVICE);获取摄像头的管理者cameraManager,
foreach遍历所有的摄像头:
CameraMetadata.LENS_FACING_BACK为后置摄像头,也可以用字符串"0"表示;
CameraMetadata.LENS_FACING_FRONT为前置摄像头"1";
cameraManager.getCameraCharacteristics(cameraId);传入指定id获取该摄像头的characteristics,
通过CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES字段获取支持的FPS(前后摄像头一样);
通过CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP字段获取设备支持的预览尺寸;
预览尺寸指相机把画面输出到手机屏幕上供用户预览的尺寸,一般手机都会支持多个不同尺寸供用户选择,通常在不超过手机分辨率下,选择越大的尺寸,预览画面越清晰.
(荣耀10 分辨率为2280x1080,我选择map.getOutputSizes(SurfaceTexture.class)[2],即2160x1064)
/**
* 遍历所有摄像头,检查是否可用