目前公司的项目都是,针对生物认证来进行一些验证之类的功能,比方说,交互式活体检测,人脸1v1(对比),人脸1vN(搜索)。用系统自带的相机?当然是不够用了,不够用那就自定义啦,就像是前几天七夕,没对象怎么办,当然是new一个了。对了结尾还提供了一个调用极其简单的相机工具类。
通常我们调用相机的话,无非就是Intent打开系统自带的相机,要自定义相机的话,也要通过Android框架所提供的API让我们控制相机硬件,来达到我们的需求。
使用API来控制相机我们需要用到关键类和接口:
Camera类
//判断是否存在相机硬件
FEATURE_CAMERA : 后置相机
FEATURE_CAMERA_FRONT : 前置相机
PackageManager pm = getPackageManager();
boolean hasACamera = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);
//打开相机
camera = Camera.open();//默认打开后置相机
camera = Camera.open(0);//也可传递参数打开指定相机 0为后置 1为前置
//设置相机参数
Camera.Parameters parameters = camera.getParameters();//得到摄像头的参数
parameters.setJpegQuality(100);//设置照片的质量
parameters.setPreviewSize(640,480);//设置预览尺寸
parameters.setPictureSize(640,480);//设置照片尺寸
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续对焦模式
//Camera.Parameters.FOCUS_MODE_AUTO; //自动聚焦模式
//Camera.Parameters.FOCUS_MODE_INFINITY;//无穷远
//Camera.Parameters.FOCUS_MODE_MACRO;//微距
//Camera.Parameters.FOCUS_MODE_FIXED;//固定焦距
camera.setParameters(parameters);
//设置相机旋转角度
//有些手机上面会出现旋转90度的情况(Android兼容性问题)所以我们要在这里适配一下
Camera.CameraInfo info = new Camera.CameraInfo();
//获取摄像头信息
Camera.getCameraInfo(cameraId, 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;
}
camera.setDisplayOrientation(result);
//开始预览以及结束预览
camera.setPreviewDisplay(surfaceHolder);//通过SurfaceView显示取景画面
camera.startPreview();//开始预览
camera.stopPreview();//结束预览
camera.release();
//拍照
camera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
//拍照 byte数据即是照取的图片 可以直接转换成bitmap
//此方法只会调用一次 建议写在点击事件中
Bitmap mbitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
});
//获取实时的照相机数据
camera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
//这里byte数据即是实时获取的帧数据 只要相机正在预览就会一直回调此方法
//需要注意的是 这里的byte数据不能够直接使用 需要转换下格式
Bitmap bmp = null;
try {
YuvImage image = new YuvImage(bytes, ImageFormat.NV21, 640, 480, null);
if (image != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, 640, 480), 80, stream);
bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
stream.close();
}
} catch (Exception ex) {
Log.e("Sys", "Error:" + ex.getMessage());
}
}
});
SurfaceView 控件
//获取SurfaceHolder对象
SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();
// 设置 Surface 格式
// 参数: PixelFormat中定义的 int 值 ,详细参见 PixelFormat.java
mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
//保持屏幕常亮(可选)
mSurfaceHolder.setKeepScreenOn(true);
// 添加 Surface 的 callback 接口
mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
//在 Surface 首次创建时被立即调用:获得焦点时。一般在这里开启相机预览
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
//在 Surface 格式 和 大小发生变化时会立即调用,可以在这个方法中更新 Surface
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//在 Surface 被销毁时立即调用:失去焦点时。一般在这里将相机预览停止销毁
}
});
public class CameraActivity extends BaseActivity{
private Camera camera;
private SurfaceView mSurfaceView;
private boolean isPreview = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
mSurfaceView = findViewById(R.id.sv);
// 获得 SurfaceHolder 对象
SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();
// 设置 Surface 格式
// 参数: PixelFormat中定义的 int 值 ,详细参见 PixelFormat.java
mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
// 如果需要,保持屏幕常亮
mSurfaceHolder.setKeepScreenOn(true);
// 添加 Surface 的 callback 接口
mSurfaceHolder.addCallback(mSurfaceCallback);
findViewById(R.id.btn_camera).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
camera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
//进行拍照操作
}
});
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if(camera != null) {
camera.release();
}
finish();
}
private SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
// Camera,open() 默认返回的后置摄像头信息
camera = Camera.open();
//此处也可以设置摄像头参数
Camera.Parameters parameters = camera.getParameters();//得到摄像头的参数
parameters.setJpegQuality(100);//设置照片的质量
parameters.setPreviewSize(1920,1080);//设置预览尺寸
parameters.setPictureSize(1920,1080);//设置照片尺寸
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续对焦模式
camera.setParameters(parameters);
//设置角度,此处 CameraId 我默认 为 0 (后置)
// CameraId 也可以 通过 参考 Camera.open() 源码 方法获取
setCameraDisplayOrientation(CameraActivity.this,0,camera);
camera.setPreviewDisplay(surfaceHolder);//通过SurfaceView显示取景画面
camera.startPreview();//开始预览
isPreview = true;//设置是否预览
} catch (IOException e) {
Log.e("surfaceCreated", e.toString());
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
if(camera != null){
if(isPreview){//正在预览
camera.stopPreview();
camera.release();
}
}
}
};
/**
* 设置 摄像头的角度
* @param activity 上下文
* @param cameraId 摄像头ID(假如手机有N个摄像头,cameraId 的值 就是 0 ~ N-1)
* @param camera 摄像头对象
*/
public static void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) {
Camera.CameraInfo info = new Camera.CameraInfo();
//获取摄像头信息
Camera.getCameraInfo(cameraId, 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; // compensate the mirror
} else {
// 后置摄像头
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
}
别忘了添加权限
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
//首先在布局中注册控件
<com.xzq.camera.CameraPreview
android:id="@+id/cp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
//然后在你想打开相机的地方
//找到控件
CameraPreview cp = findViewById(R.id.cp);
CameraUtil.INSTANCE.setPreviewView(cp);//设置预览控件
//设置预览监听
CameraUtil.INSTANCE.setOnCameraListener(new OnCameraListener() {
@Override
public void onCameraDataFetched(byte[] bytes) {
//实时获取相机数据
}
@Override
public void onError(CameraError cameraError) {
//打开相机错误
}
});
是不是极其简单,跟上边的一比,我都不明白我为什么要写上边的东西。。。。。
相机jar包的下载地址:https://download.csdn.net/download/qq_38001118/10615455
如果有什么扩展的需求或者我有什么遗失和错误欢迎评论,我会第一时间回复和更新。