zoukankan      html  css  js  c++  java
  • Android 人脸识别签到(二)

    学习完百度人脸API的调用,现在即可开发自己的人脸识别签到系统,下面作者先贴上部分功能源码来给大家参考和学习

    (一)百度人脸库的人脸验证

    1°   获取待识别的照片

    既然是人脸认证 那么当然首先得向百度人脸库添加你的人脸

    然后再把你需要进行人脸识别的照片与百度人脸库的人脸进行校对,如果校对成功,即签到打卡成功

    关于获取带人脸识别的照片,作者采取了两种方式获取(即时拍照、从相册导入)

    即时拍照:

    Camera.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
            StrictMode.setVmPolicy(builder.build());
            builder.detectFileUriExposure();            //Android7.0拍照必加   且需要在方法类前加@SuppressLint("NewApi")
    
            File outputImage = new File(Environment.getExternalStorageDirectory() + File.separator + "face.jpg");     //临时照片存储地
            try {
                if (outputImage.exists()) {
                    outputImage.delete();              //若临时存储地已有照片则delete
                }
                outputImage.createNewFile();           //临时存储地创建新文件
            } catch (IOException e) {
                e.printStackTrace();
            }
            imageUri = Uri.fromFile(outputImage);              //获取临时存储地Uri
            ImagePath = outputImage.getAbsolutePath();           //得到绝对路径
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);    //跳转相机
            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);                          //相片输出路径
            startActivityForResult(intent, CAMERA);                        //返回照片路径
        }
    });

    从相册直接获取:

           getImage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent in = new Intent(Intent.ACTION_PICK);      //选择数据
                    in.setType("image/*");                //选择的数据为图片
                    startActivityForResult(in, Photo_ALBUM);
                }
            });

    获取照片之后需要把照片显示到手机APP界面上,给用户做一个预览   也就是方法startActivityForResult的作用

     关于拍照旋转角度问题解释(https://www.jianshu.com/p/6179f16907dc)

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            // 相册选择图片
            if (requestCode == Photo_ALBUM) {
                if (data != null) {
                    Uri uri = data.getData();           //获取图片uri
                    Cursor cursor = getContentResolver().query(uri, null, null, null, null);
                    cursor.moveToNext();      
                    ImagePath = cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA));   //获得图片的绝对路径
                    cursor.close();          
                    resizePhoto();         //将图片变成缩小的bitmap  方法后贴
                    int degree = getPicRotate(ImagePath);        //获取拍照图片的旋转角度   可以查一下我给出的地址  getPicRotate方法在下面
                    Matrix m = new Matrix();    //对图形处理
                    m.setRotate(degree);        //旋转
                    lastp = Bitmap.createBitmap(myBitmapImage, 0, 0, myBitmapImage.getWidth(), myBitmapImage.getHeight(), m, true);    //获取缩小且旋转好的图片
                    myPhoto.setImageBitmap(lastp);       //显示图片
                    Log.i("图片路径", ImagePath);
                }
            } else if (requestCode == CAMERA) {
                try {
                    resizePhoto();
                    int degree = getPicRotate(ImagePath);          //获取旋转角度
                    Matrix m = new Matrix();    //对图形处理的类
                    m.setRotate(degree);        //旋转
                   
                   lastp = Bitmap.createBitmap(myBitmapImage, 0, 0, myBitmapImage.getWidth(), myBitmapImage.getHeight(), m, true);
                    myPhoto.setImageBitmap(lastp);       //显示图片
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

     

    获取旋转角度

     1  public int getPicRotate(String path) {          //旋转图片
     2         int degree = 0;
     3         try {
     4             ExifInterface exifInterface = new ExifInterface(path);
     5             int orientation = exifInterface.getAttributeInt(
     6                     ExifInterface.TAG_ORIENTATION,
     7                     ExifInterface.ORIENTATION_NORMAL);          //命名空间 命名空间所属属性
     8             switch (orientation) {
     9                 case ExifInterface.ORIENTATION_ROTATE_90:
    10                     degree = 90;
    11                     break;
    12                 case ExifInterface.ORIENTATION_ROTATE_180:
    13                     degree = 180;
    14                     break;
    15                 case ExifInterface.ORIENTATION_ROTATE_270:
    16                     degree = 270;
    17                     break;
    18             }
    19         } catch (IOException e) {
    20             e.printStackTrace();
    21         }
    22         return degree;
    23     }

    2°   上传待查照片到百度开发平台,与百度人脸库里已存的照片进行匹配

    既然已经获取了待查照片,那么现在即把照片与人脸库的已有照片进行匹配,若百度人脸库存在此人,那么就匹配成功(即签到成功)

    1.当点击识别按钮后,将待查照片上传,并创建一个线程用于处理放回的结果

     detect.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    res = null;
                    tip.setVisibility(View.VISIBLE);         //识别中提示   在Android界面显示
                    if (myBitmapImage == null) {
                        Toast.makeText(MainActivity.this, "请添加图片!!!", Toast.LENGTH_LONG).show();
                        tip.setVisibility(View.GONE);         //隐藏    识别中提示
                    }
                    else if(Class.getText().toString().trim().equals("请输入查课节次")==true){
                        Toast.makeText(MainActivity.this, "请输入查课节次!!!", Toast.LENGTH_LONG).show();
                        tip.setVisibility(View.GONE);
                        }
                    else {
                           //对于上传的图片进行处理
                        int degree = getPicRotate(ImagePath);        
                        Matrix m = new Matrix();    //对图形处理
                        m.setRotate(degree);        //旋转
                        bitmapSmall = Bitmap.createBitmap(myBitmapImage, 0, 0, myBitmapImage.getWidth(), myBitmapImage.getHeight(), m, true);
                        ByteArrayOutputStream stream = new ByteArrayOutputStream();
                        //图片转数据流
                        bitmapSmall.compress(Bitmap.CompressFormat.JPEG, 100, stream);     //图片压缩格式,压缩率,文件输出流对象
                        final byte[] arrays = stream.toByteArray();                 //转成二进制数组
                        final String pic = android.util.Base64.encodeToString(arrays, Base64.DEFAULT);   //获取图片 Base64格式的String
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                HashMap<String, String> options = new HashMap<>();     
                                options.put("quality_control", "NORMAL");                  //质量控制
                                options.put("liveness_control", "LOW");                      //活体控制
                                options.put("max_user_num", "3");                         //返回结果的最大个数
    
                                String groupId = "ruan1,ruan2";                              //查询的人脸组
                                String imageType = "BASE64";                                    //上传的图片格式
    
                                AipFace client = new AipFace("15119543", "lwxkzZOqjm4bcN2DmHoe8giy", "skYUhhZAfsUCFsBud7VQPIdWPvMt7tOM");      
                                client.setConnectionTimeoutInMillis(2000);          //超时设置
                                client.setSocketTimeoutInMillis(6000);
    
                                res = client.search(pic, imageType, groupId, options);         //获取查询结果集
    
                                try {
                                    Message message = Message.obtain();
                                    message.what = 1;
                                    message.obj = res;
                                    handler.sendMessage(message);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    Message message = Message.obtain();
                                    message.what = 2;
                                    handler.sendMessage(message);
                                }
    
    
                            }
                        }).start();
                    }
                }
            });
        }

    2.当上传完图片后,即可获取查询结果集,那么将结果集交由线程进行处理

    private Handler handler = new Handler() {
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                JSONObject jsonObject=null;
                String classes = null;
                String Record_class = null;
                String PId =  null;
                String name =  null;
                if (msg.what == 1) {                     //放回有效的结果集  
                    JSONObject res = (JSONObject) msg.obj;
                    System.out.println(res);
                    error_code = res.optString("error_code");        //看是否查询成功
                    System.out.println(error_code);
                    if (error_code.equals("0") == true) {
                        JSONArray TEMP = res.optJSONObject("result").optJSONArray("user_list");       //获取查询结果集的  用户列表
    
                        try {
                            jsonObject = TEMP.getJSONObject(0); 
                            String Tscore = jsonObject.getString("score");                   
                             classes = jsonObject.getString("group_id");                  //这里获取classes到获取name  是为了后面实现将查询结果同步到服务器数据库做准备
                             Record_class = Class.getText().toString().trim();
                             PId = jsonObject.getString("user_id");
                             name = jsonObject.getString("user_info");
                            System.out.println(classes+Record_class+ PId+ name);
                            System.out.println(jsonObject);
                            System.out.println(Tscore);
                            score = Double.parseDouble(Tscore);                //获取最相似人脸分数    因为最相似人脸会直接放到查询的user_list的第一个          
                            System.out.println(score);
    
                            //  score=Math.ceil(Double.parseDouble(Tscore));
                        } catch (JSONException SE) {
                            SE.printStackTrace();
                        }
                        if (score >= 75) {                                //若相似度大于75
                            addrecord(classes,Record_class,PId,name);                 //服务器数据库添加查询成功的结果
                            } else
                            Toast.makeText(MainActivity.this, "打卡失败,请重新导入照片", Toast.LENGTH_LONG).show();
    
                            myBitmapImage = null;
                            InitBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.show, null);
                            tip.setVisibility(View.GONE);
                             myPhoto.setImageBitmap(InitBitmap);
                    }
                    else
                        Toast.makeText(MainActivity.this, "打卡失败,请重新导入照片", Toast.LENGTH_LONG).show();
                        tip.setVisibility(View.GONE);
                }
    
            }
        };

    关于addrecord方法,我用了Android的volley框架来进行与自己服务器后台的交互

     public void addrecord(final String classes,final String Record_class,final String PId,final String name){
            Log.d("addrecord",classes+","+PId+","+name);
            //请求地址,需要换接口
    
            String url="http://47.106.10.15:8080/FtoFserver/FtoFserver/addRecord";     //服务器后台的接口   我接口使用Servelet写的
          
            String tag = "addrecord";
            //取得请求队列
            RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);          //传参为当前的context
            //防止重复请求,所以先取消tag标识的请求队列
            requestQueue.cancelAll(tag);
            //创建StringRequest,定义字符串请求的请求方式为POST(省略第一个参数会默认为GET方式)
            StringRequest request = new StringRequest(Request.Method.POST, url,
                    new Response.Listener<String>() {
                        @Override
                        public void onResponse(String response) {
                            Log.d("response",response);
                            try {
                                JSONObject jsonObject = new JSONObject(response);        //获取的到的后台回应
                                temp = jsonObject.getString("canLogin");
                                if(temp.equals("true")){
                                    //等待接口
                                    System.out.println("发布成功");
                                    Toast.makeText(MainActivity.this, "打卡成功!!!", Toast.LENGTH_LONG).show();
                                }else {
                                    System.out.println("发布失败");
                                    Toast.makeText(MainActivity.this, "网络延迟,请重新上传!!!", Toast.LENGTH_LONG).show();
                                }
                            } catch (JSONException e) {
                                //做自己的请求异常操作,如Toast提示(“无网络连接”等);
                                e.printStackTrace();
                            }
                        }
                    }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    //做自己的响应错误操作,如Toast提示(“请稍后重试”等)
                    Log.d("error",error.toString());
                }
            }) {
                @Override
                protected Map<String, String> getParams() throws AuthFailureError {
                    Map<String,String> params = new HashMap<>();                      //将打卡成功的人的信息同步到自己的服务器端
                    params.put("classes", classes);                                    //传参到服务器接口
                    params.put("Record_class",Record_class);
                    params.put("PId",PId);
                    params.put("name",name);
                    System.out.println(name);
                    return params;
                }
    
            };
    
            //设置Tag标签
            request.setTag(tag);
            request.setRetryPolicy(new DefaultRetryPolicy(20*1000,1,1.0f));
            //将请求添加到队列中
            requestQueue.add(request);
        }

    3°当验证完所有人脸,又把验证结果同步到自己事先部署的服务器端后,即完成了所以打卡操作

    接下来   就可以用普通的servelet来获取服务器中存储的所有总的签到结果

    即可导出已签到的人和未签到的人  

    补充 :

    当然百度人脸库的更新、添加、删除也与打卡操作大同小异   也可以编辑类似上面的代码 来直接在安卓端操作

    例如:

    你可以事先在百度人脸库创建分组,然后往分组添加人脸的时候,同时完成添加人脸和添加自己服务端的人脸花名册信息操作

     

    这样既可以抛去对直接去操作百度控制台的的操作

     

    查询已经签到人:

    可以直接查看自己服务器端的签到记录获取

     

    查看未签到人:

    可以通过服务器端的  班级花名册  减去签到记录已有的人

    既可以获取未签到的人   

    整个项目我已经上传到github  欢迎大家学习

    https://github.com/MrBling/FacetoFace(FacetoFace用Android studio导入项目,FtoFServer是我服务器端的代码  想看的话用IDEA导入项目即可)

  • 相关阅读:
    Linux-3.14.12内存管理笔记【构建内存管理框架(3)】
    Linux-3.14.12内存管理笔记【构建内存管理框架(2)】
    Linux-3.14.12内存管理笔记【构建内存管理框架(1)】
    Linux-3.14.12内存管理笔记【建立内核页表(3)
    Linux power supply class(1)_软件架构及API汇整【转】
    Linux-3.14.12内存管理笔记【建立内核页表(2)】-低端内存的建立
    Linux-3.14.12内存管理笔记【建立内核页表(1)】
    linux防火墙相关 iptables
    shell 备份 source code
    crontab清理日志
  • 原文地址:https://www.cnblogs.com/Mr-BING/p/10160920.html
Copyright © 2011-2022 走看看