时间:2019-09-03

概述:人脸识别

Android实现简单的人脸识别,人脸检测(这里用的是科大讯飞的人脸识别),因此需要此库导入后,测试本代码:

private final static String TAG = MainActivity.class.getSimpleName();

private SurfaceView mPreviewSurface;//用于显示预览图像

private SurfaceView mFaceSurface;//用于绘制检测人脸的返回信息

private SurfaceHolder mSurfaceHolder;//纹理控制器

private ImageButton changeCamera;//切换摄像头按钮

private Camera mCamera;//摄像头对象

private int mCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;//设置为默认开启前置摄像头

// 默认设置640*480,截至目前也只是支持640*480

private int PREVIEW_WIDTH = 640;

private int PREVIEW_HEIGHT = 480;

// 预览帧数据存储数组和缓存数组

private byte[] nv21;

private byte[] buffer;

// 缩放矩阵

private Matrix mScaleMatrix = new Matrix();

// 加速度感应器,用于获取手机的朝向

private Accelerometer accelerometer;

private FaceDetector mFaceDetector;//调用讯飞的SDK来实现人脸识别

private boolean stop;//人脸检测开关

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

SpeechUtility.createUtility(this, "appid=" + "5833f456"); //设置AppKey用于注册,AppID

initView();//初始化布局

initData();//初始化数据

requestPermission(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1000);

}

@Override

public void permissionSuccess(int requestCode) {

super.permissionSuccess(requestCode);

if (requestCode == 1000){

Toast.makeText(MainActivity.this,"获取文件写入权限成功!",Toast.LENGTH_SHORT).show();

}

if (requestCode == 2000){

openCamera();//打开摄像头

}

}

/**

* 用于显示摄像头拍摄到的图像

*/

private SurfaceHolder.Callback mPreviewCallback = new SurfaceHolder.Callback() {

@Override

public void surfaceDestroyed(SurfaceHolder holder) {

closeCamera();//关闭摄像头,并释放资源

}

@Override

public void surfaceCreated(SurfaceHolder holder) {

requestPermission(new String[]{Manifest.permission.CAMERA},2000);

}

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

mScaleMatrix.setScale(width / (float) PREVIEW_HEIGHT,

height / (float) PREVIEW_WIDTH);//设置缩放比例

}

};

/**

* 设置纹理尺寸

*/

private void setSurfaceSize() {

DisplayMetrics metrics = new DisplayMetrics();

getWindowManager().getDefaultDisplay().getMetrics(metrics);

int width = metrics.widthPixels;

int height = (int) (width * PREVIEW_WIDTH / (float) PREVIEW_HEIGHT);

RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width, height);

params.addRule(RelativeLayout.ALIGN_PARENT_TOP);

mPreviewSurface.setLayoutParams(params);

}

/**

* 初始化数据

*/

private void initData(){

nv21 = new byte[PREVIEW_WIDTH * PREVIEW_HEIGHT * 2];

buffer = new byte[PREVIEW_WIDTH * PREVIEW_HEIGHT * 2];

accelerometer = new Accelerometer(this);

mFaceDetector = FaceDetector.createDetector(this, null);//实例化人脸检测对象

}

/**

* 初始化控件

*/

private void initView() {

mPreviewSurface = (SurfaceView) findViewById(R.id.preview);

mFaceSurface = (SurfaceView) findViewById(R.id.face);

changeCamera = (ImageButton) findViewById(R.id.change);

mPreviewSurface.getHolder().addCallback(mPreviewCallback);

mSurfaceHolder = mFaceSurface.getHolder();

mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);

mFaceSurface.setZOrderOnTop(true);

// 点击SurfaceView,切换摄相头

changeCamera.setOnClickListener(v -> {

// 只有一个摄相头,不支持切换

if (Camera.getNumberOfCameras() == 1) {

Toast.makeText(this, "只有后置摄像头,不能切换", Toast.LENGTH_SHORT).show();

return;

}

closeCamera();

if (Camera.CameraInfo.CAMERA_FACING_FRONT == mCameraId) {

mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;

} else {

mCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;

}

openCamera();

});

setSurfaceSize();

}

/**

* 打开摄像头

*/

private void openCamera() {

if (mCamera != null) {

return;

}

try {

mCamera = Camera.open(mCameraId);

if (Camera.CameraInfo.CAMERA_FACING_FRONT == mCameraId) {

Toast.makeText(this, "前置摄像头已开启,点击可切换", Toast.LENGTH_SHORT).show();

} else {

Toast.makeText(this,"后置摄像头已开启,点击可切换",Toast.LENGTH_SHORT).show();

}

setCameraDisplayOrientation(this, mCameraId, mCamera);//设置摄像头的预览方向

} catch (Exception e) {

e.printStackTrace();

closeCamera();

return;

}

//获取摄像头参数对象

Camera.Parameters params = mCamera.getParameters();

//设置预览的格式

params.setPreviewFormat(ImageFormat.NV21);

//设置预览的分辨率,这里设置640*480,到目前为止只支持该分辨率的人脸检测

params.setPreviewSize(PREVIEW_WIDTH, PREVIEW_HEIGHT);

//给摄像头设置参数配置

mCamera.setParameters(params);

//给摄像头设置预览回到,这里使用的Lambda表达式代表的只有一个回调函数的匿名内部类

mCamera.setPreviewCallback((data, camera) -> System.arraycopy(data, 0, nv21, 0, data.length));

try {

mCamera.setPreviewDisplay(mPreviewSurface.getHolder());

mCamera.startPreview();

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 释放摄像头资源

*/

private void closeCamera() {

if (null != mCamera) {

mCamera.setPreviewCallback(null);

mCamera.stopPreview();

mCamera.release();

mCamera = null;

}

}

@Override

protected void onResume() {

super.onResume();

if (null != accelerometer) {

accelerometer.start();

}

stop = false;

new Thread(()->{

while (!stop) {

if (null == nv21) {

continue;

}

synchronized (nv21) {

System.arraycopy(nv21, 0, buffer, 0, nv21.length);

}

int direction = Accelerometer.getDirection();// 获取手机朝向

boolean frontCamera = (Camera.CameraInfo.CAMERA_FACING_FRONT == mCameraId);

if (frontCamera) {

direction = (4 - direction) % 4;// 0,1,2,3,4分别表示0,90,180,270和360度

}

String result = mFaceDetector.trackNV21(

buffer, PREVIEW_WIDTH, PREVIEW_HEIGHT, 1, direction);//获取人脸检测结果

FaceRect face = Result.result(result);//获取返回的数据

Log.e(TAG, "result:" + result);//输出检测结果,该结果为JSON数据

Canvas canvas =mSurfaceHolder.lockCanvas();//锁定画布用于绘制

if (null == canvas) {

continue;

}

canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);//清除之前的绘制图像

canvas.setMatrix(mScaleMatrix);

if (face == null) {

mSurfaceHolder.unlockCanvasAndPost(canvas);

continue;

}

if (face != null) {

face.bound = DrawFaceRect.RotateDeg90(face.bound, PREVIEW_HEIGHT);//绘制人脸的区域

if (face.point != null) {//绘制脸上关键点

for (int i = 0; i < face.point.length; i++) {

face.point[i] = DrawFaceRect.RotateDeg90(face.point[i], PREVIEW_HEIGHT);

}

//绘制人脸检测的区域

DrawFaceRect.drawFaceRect(canvas, face, PREVIEW_WIDTH, frontCamera);

}

} else {

Log.e(TAG, "没有检测出人脸");

}

mSurfaceHolder.unlockCanvasAndPost(canvas);

}

}).start();

}

解析人脸返回结果:

FaceRect rect = null;

if (TextUtils.isEmpty(json)) {

return null;

}

try {

JSONObject joResult = new JSONObject(json);

JSONArray items = joResult.getJSONArray("face");//解析face数组

JSONObject position = items.getJSONObject(0).getJSONObject("position");

//获取人脸检测框数据

rect = new FaceRect();

rect.bound.left = position.getInt("left");//左边起始位置点

rect.bound.top = position.getInt("top");//上端起始位置点

rect.bound.right = position.getInt("right");//右边结束位置点

rect.bound.bottom = position.getInt("bottom");//下端结束位置点

// 提取关键点数据

JSONObject landmark = items.getJSONObject(0).getJSONObject("landmark");

int keyPoint = landmark.length();//人脸检测点数据

rect.point = new Point[keyPoint];//人脸检测点数组

Iterator it = landmark.keys();//使用迭代器解析人脸监测点数据

int point = 0;

while (it.hasNext()) {//检测点,的坐标

String key = (String) it.next();

JSONObject object = landmark.getJSONObject(key);

rect.point[point] = new Point(object.getInt("x"), object.getInt("y"));

point++;

}

} catch (JSONException e) {

e.printStackTrace();

}

return rect;

android 人脸识别边框_Android实现简单的人脸识别相关推荐

  1. android 弹窗有边框_Android 多种简单的弹出框样式设置代码

    简介 这是一个基于AlertDialog和Dialog这两个类封装的多种弹出框样式,其中提供各种简单样式的弹出框使用说明.同时也可自定义弹出框. 特性 1.使用链式开发代码简洁明了 2.所有的弹出框样 ...

  2. android 人脸识别边框_android Arcface人脸识别框/人脸抓拍框/人脸追踪框

    为什么要改? 先来看看sdk demo中提供的人脸框样式,这个框看上去并不是非常美观(个人觉得) 再看看下面这个框是不是就要顺眼一点 怎么换? 先来看看原始的画法: @Override public ...

  3. android 人脸识别边框_android自定义Arcface人脸识别框/人脸抓拍框/人脸追踪框

    为什么要改? 先来看看sdk demo中提供的人脸框样式,这个框看上去并不是非常美观(个人觉得) 在这里插入图片描述 再看看下面这个框是不是就要顺眼一点 在这里插入图片描述 怎么换? 先来看看原始的画 ...

  4. 人脸识别手机端APK分享 | 极速体验人脸识别功能 创建一个简单的人脸识别手机APP程序

    1.前言 虹软公司提供免费离线人脸识别,对于开发者提供了比较友好.完整的可配置demo.但是如需直接体验功能,还是要花一点时间去完成项目编译.配置等一系列工作,对于初学者.不怎么熟悉整个项目的人来说可 ...

  5. android绘制半圆弧线_android实现简单圆弧效果

    最近项目完成就开始搞一些有用没用的东西,以前面试的时候有人问我那种圆弧效果怎么做,还问我翻牌效果,我只看过,没有做过,现在有空了,而且想到可能会用到就做个简单的 圆弧很简单,自定义个View,创建个P ...

  6. android 弹窗有边框_android中常用的弹出提示框

    我们在平时做开发的时候,免不了会用到各种各样的对话框,相信有过其他平台开发经验的朋友都会知道,大部分的平台都只提供了几个最简单的实现,如果我们想实现自己特定需求的对话框,大家可能首先会想到,通过继承等 ...

  7. 关于Vuforia扫描识别图片,最简单的设置识别区域

    因为需要做个Vuforia扫描并设置识别区域,查了一些资料发现网上并没太多介绍这块内容. 有看到一个帖子上给了两个解决方案,一个是图片裁剪,但是这个方法太烦了.还有个是遮罩不过因为Vuforia插件中 ...

  8. OCR识别缺点_常用的OCR文字识别软件有哪些_软件动态论坛

    随着大家办公需求的增加,办公软件如雨后春笋般纷纷面世,旨在提高大家的工作效率,OCR文字识别软件便是不可缺少的办公软件之一.那么,有哪些专业又好用的OCR文字识别软件呢?小编来为大家推荐几款,以供参考 ...

  9. android 人脸识别边框_人脸框抠图如何实现

    最近在尝试做一个人脸识别项目,在对比几款主流人脸识别SDK后,采用了虹软的Arcface SDK,因为它提供了免费版本,并且可以离线使用,接入难度也比较低.项目中有一个需求就是显示检测到的人脸,但是如 ...

  10. android 人脸识别边框_【技术分享】虹软人脸识别 - Android Camera实时人脸追踪画框适配...

    在使用虹软人脸识别Android SDK的过程中 ,预览时一般都需要绘制人脸框,但是和PC平台相机应用不同,在Android平台相机进行应用开发还需要考虑前后置相机切换.设备横竖屏切换等情况,因此在人 ...

最新文章

  1. 广州Robotaxi铁三角又落地,文远知行商业化通行证摊牌
  2. java的内省有用么_JAVA中的内省使用
  3. 深度学习未来十大趋势
  4. mysql proxy读写分离实现_使用mysql-proxy实现读写分离
  5. Raft算法的Leader选举和日志复制过程
  6. 在 MyEclipse 中配置 tomcat
  7. SAP 开发陷阱一箩筐(05)——绘制屏幕时无法给单选按钮分组
  8. Softether软件原理分析
  9. 采用UltraISO软碟通制作Dos启动盘教程
  10. 小型oa服务器系统,大型、中小型企业OA系统实施差异对比
  11. RGB色彩,HSV色彩模式、灰度图,亮度,对比度,饱和度、图像平滑、降噪、锐化、增强
  12. 【推荐】泰坦尼克号乘客生存分析——用机器学习告诉你,如果你在当时的船上,有多大机率生还?
  13. 用c语言写出一个金字塔
  14. 导出带有表格的word文件时,换页自带表头,避免复杂的表格数行数计算
  15. 项管行知02--工作环境
  16. 在谷歌上安装倍速播放的插件video-speed-controller
  17. 如何无损放大图片?用这5个图片无损放大工具,图片方法也超高清
  18. Android软件开发之获取通讯录联系人信息
  19. 丰沛数_不足数_完全数
  20. Linux命令--tail

热门文章

  1. 21天学通C语言-学习笔记(6)
  2. 脚本录制软件python 按键精灵 tc_喜讯。tc也能录脚本了!录制鼠标键盘,tc脚本录制工具!!...
  3. 哈理工OJ 1184 早起一水(水题)
  4. 面试官:说说什么是 Java 内存模型(JMM)?
  5. NXP iMX8基于eIQ框架测试Machine Learning
  6. 『Asp.Net 组件』Asp.Net 服务器组件 内嵌CSS:将CSS封装到程序集中
  7. 微信信息轰炸【简易版】
  8. 算法导论(第三版)第一章习题答案
  9. 基于 attention 机制的 LSTM 神经网络 超短期负荷预测方法学习记录
  10. 天翼网关获取超级密码