【这段时间有点忙,终于截止今天2018.06.22完成了人脸识别的最后一道程序——活体检测之眨眨眼和张张嘴】

关于人脸识别的内容我之前也写过好几篇博文,其中有: 
{java实现人脸识别源码} 
{C#winforms实现windows窗体人脸识别} 
{人脸识别活体检测测试案例} 
大家可以去看看,其中兼容性也比较良好,支持常用浏览器,火狐、谷歌、360、UC浏览器以及opera浏览器,源码也已经上传成功,所需要的JS文件和jar也都上传到资源页。

好了,我们废话不多说,先来说说今天的内容。 
眨眨眼和张张嘴在哪里用的到呢?如果大家不知道其他的软件,大家肯定知道支付宝软件吧,其中支付宝软件登陆的时候就会语音提示眨眨眼和张张嘴来验证是不是本人登陆(限制照片登陆)

以前刚开始写的时候我写的人脸识别用照片也可以识别,然后好多粉丝留言说这太不安全了,还有几个用嫌弃的眼神对我说:你这做的还有啥用,我拿着你的照片来登陆,居然能登陆成功,还不如以前的密码登陆安全呢。(其实他没做出来~),我也没说啥,毕竟是自己做的不完善呢,忍气吞声继续深入研究。终于做出来了后来的活体检测,也就是上面的第二个链接! 但是…… 这个活体检测有时候会失误!会失误!会失误!!! 这是个很大的bug,于是我就开始开发现在的眨眨眼和张张嘴~


一、首先我来说一下运行过程:

首先进入页面,login.jsp中,点击检测按钮

接着你会听到语音提示:现在请张张嘴(这个语音提示可是专门找美女录得音呢~) 
你就按照语音提示张张嘴就可以了,张合张合重复一遍就大概可以验证成功了,接着你就会听见语音提示:现在请眨眨眼,这时候你眨眨眼就行了,验证通过会进入我的网站,期间如果你的脸没有放置好的话就会提示:

当你看到提示这个的时候你把脸调整的放到框内就可以了。实在不行你就刷新一下网页重新来一遍吧。


二、技术分析

技术方面有以下几个步骤:

第一,js调用前台摄像头读取人脸信息,提交到后台的FaceServlet中,通过ajax进行交互,参数分别是:

type : “post”,//提交方式

url : “faceServlet”,//请求地址

data : {

“img” : imgData1,

“tag” : “eye”//区分是眨眼还是张嘴

}//数据

4.dataType : “json”

上面就是ajax请求的参数,然后写个回调函数就可以了。

第二、拿着Base64图像数据之后去检测去,检测回来的数据如下所示:


“timestamp”: 1528371144, 
“result”: { 
“face_list”: [{ 
“expression”: { 
“probability”: 0.9999684095, 
“type”: “none” 
}, 
“face_probability”: 0.9626089931, 
“glasses”: { 
“probability”: 0.9998494387, 
“type”: “common” 
}, 
“location”: { 
“height”: 307, 
“rotation”: 2, 
“width”: 273, 
“left”: 296.1046143, 
“top”: 163.5777588 
}, 
“landmark72”: [ 

“y”: 241.360199, 
“x”: 292.4519043 
}, 

“y”: 284.3699341, 
“x”: 295.9116211 
}, 

“y”: 328.4156189, 
“x”: 304.021759 
}, 

“y”: 371.3819275, 
“x”: 314.0935364 
}, 

“y”: 416.5806274, 
“x”: 333.3151245 
}, 

“y”: 459.6279297, 
“x”: 370.47229 
}, 

“y”: 476.2438354, 
“x”: 412.0462036 
}, 

“y”: 469.1072998, 
“x”: 457.7119141 
}, 

“y”: 435.0166626, 
“x”: 501.7189941 
}, 

“y”: 390.2756348, 
“x”: 532.2461548 
}, 

“y”: 345.0927124, 
“x”: 548.138916 
}, 

“y”: 299.1921692, 
“x”: 559.2930298 
}, 

“y”: 254.285141, 
“x”: 565.3004761 
}, 

“y”: 230.1785583, 
“x”: 329.6694946 
}, 

“y”: 222.2650757, 
“x”: 343.285614 
}, 

“y”: 220.7796631, 
“x”: 356.7460938 
}, 

“y”: 223.9135742, 
“x”: 371.3406677 
}, 

“y”: 233.6182861, 
“x”: 385.2095947 
}, 

“y”: 235.2540588, 
“x”: 370.6172485 
}, 

“y”: 236.2314148, 
“x”: 356.4389343 
}, 

“y”: 234.2461243, 
“x”: 341.9369507 
}, 

“y”: 227.4796143, 
“x”: 355.9927368 
}, 

“y”: 193.4365387, 
“x”: 313.8055115 
}, 

“y”: 170.465332, 
“x”: 331.9764404 
}, 

“y”: 166.3371429, 
“x”: 356.399353 
}, 

“y”: 170.4036255, 
“x”: 380.4868774 
}, 

“y”: 188.2350311, 
“x”: 401.4260559 
}, 

“y”: 188.1490021, 
“x”: 379.4369202 
}, 

“y”: 186.7609863, 
“x”: 356.0379028 
}, 

“y”: 188.6333923, 
“x”: 333.6030884 
}, 

“y”: 237.4863892, 
“x”: 465.0245972


“y”: 192.1312256, 
“x”: 450.9655762 
}, 

“y”: 176.1939087, 
“x”: 474.1013794

“x”: 375.137085 
}, 

“y”: 363.3876343, 
“x”: 393.6142578 
}, 

“y”: 360.5367126, 
“x”: 422.6240845 
}, 

“y”: 366.1363525, 
“x”: 451.1436768 
}, 

“y”: 389.2103271, 
“x”: 469.8604736 
}, 

“y”: 407.2568359, 
“x”: 450.6833191 
}, 

“y”: 413.2620239, 
“x”: 420.4364014 
}, 

“y”: 403.9484863, 
“x”: 390.8678589 
}, 

“y”: 377.3647461, 
“x”: 396.2229004 
}, 

“y”: 376.8469238, 
“x”: 421.9415588 
}, 

“y”: 379.1690674, 
“x”: 447.9805908 
}, 

“y”: 390.7108154, 
“x”: 446.4016724 
}, 

“y”: 391.1112061, 
“x”: 421.5936279 
}, 

“y”: 388.0070801, 
“x”: 396.4388733 

], 
“face_token”: “05f2d8abe9fb3ff0a7b2e590c3af1b94”, 
“face_shape”: { 
“probability”: 0.5348426104, 
“type”: “oval” 
}, 
“race”: { 
“probability”: 0.9990831614, 
“type”: “yellow” 
}, 
“angle”: { 
“yaw”: 0.9113687873, 
“roll”: 2.805583239, 
“pitch”: -3.07931757 
}, 
“landmark”: [ 

“y”: 227.4796143, 
“x”: 355.9927368 
}, 

“y”: 233.886261, 
“x”: 491.254364 
}, 

“y”: 305.3646545, 
“x”: 421.223877 
}, 

“y”: 385.065155, 
“x”: 421.7819214 

], 
“, 
“quality”: { 
“completeness”: 1, 
“occlusion”: { 
“left_eye”: 0, 
“chin_contour”: 0.2168905884, 
“mouth”: 0, 
“right_cheek”: 0.02743142098, 
“left_cheek”: 0.01728247851, 
“nose”: 0.08578856289, 
“right_eye”: 0 
}, 
“blur”: 8.371096101E-7, 
“illumination”: 54 
}, 
“face_type”: { 
“probability”: 0.9988574386, 
“type”: “human” 

}], 
“face_num”: 1 
}, 
“cached”: 0, 
“error_code”: 0, 
“log_id”: 2850674365, 
“error_msg”: “SUCCESS” 
}

看到上面的json数据,我当时一看是懵逼的状态,这json解析起来有点费力,经过一番折腾,终于可以解析出来了,其中解析方法如下:public static Landmark  parsingFaceJson(JSONObject json_str){Landmark landmark = new Landmark();//开始解析json//JSONObject  dataJson=new JSONObject(json_str);//找到result节点JSONObject  response_result=json_str.getJSONObject("result");//继续找face_list节点JSONArray face_list_jsonArray=response_result.getJSONArray("face_list");JSONObject face_list_jsonObject=face_list_jsonArray.getJSONObject(0);//找到landmark(关键点)节点,4个关键点位置,左眼中心、右眼中心、鼻尖、嘴中心final JSONArray landmark_jsonArray=face_list_jsonObject.getJSONArray("landmark");//左眼中心landmark.setLeft_eye_zhongxin(new ArrayList<Double>(){{add((Double) landmark_jsonArray.getJSONObject(0).get("y")); add((Double) landmark_jsonArray.getJSONObject(0).get("x"));}});//右眼中心landmark.setRight_eye_zhongxin(new ArrayList<Double>(){{add((Double) landmark_jsonArray.getJSONObject(1).get("y")); add((Double) landmark_jsonArray.getJSONObject(1).get("x"));}});//鼻尖landmark.setNose_zhongxin(new ArrayList<Double>(){{add((Double) landmark_jsonArray.getJSONObject(2).get("y")); add((Double) landmark_jsonArray.getJSONObject(2).get("x"));}});//嘴中心landmark.setMouse_zhongxin(new ArrayList<Double>(){{add((Double) landmark_jsonArray.getJSONObject(3).get("y")); add((Double) landmark_jsonArray.getJSONObject(3).get("x"));}});//继续找landmark72节点final JSONArray landmark72_jsonArray=face_list_jsonObject.getJSONArray("landmark72");//左眼上边landmark.setLeft_eye_top(new ArrayList<Double>(){{add((Double) landmark72_jsonArray.getJSONObject(14).get("y")); add((Double) landmark72_jsonArray.getJSONObject(14).get("x"));}});//左眼下边landmark.setLeft_eye_bottom(new ArrayList<Double>(){{add((Double) landmark72_jsonArray.getJSONObject(19).get("y")); add((Double) landmark72_jsonArray.getJSONObject(19).get("x"));}});//右眼上边landmark.setRight_eye_top(new ArrayList<Double>(){{add((Double) landmark72_jsonArray.getJSONObject(32).get("y")); add((Double) landmark72_jsonArray.getJSONObject(32).get("x"));}});//右眼下边landmark.setRight_eye_bottom(new ArrayList<Double>(){{add((Double) landmark72_jsonArray.getJSONObject(36).get("y")); add((Double) landmark72_jsonArray.getJSONObject(36).get("x"));}});//嘴巴上边landmark.setMouse__top(new ArrayList<Double>(){{add((Double) landmark72_jsonArray.getJSONObject(60).get("y")); add((Double) landmark72_jsonArray.getJSONObject(60).get("x"));}});//嘴巴下边landmark.setMouse__bottom(new ArrayList<Double>(){{add((Double) landmark72_jsonArray.getJSONObject(70).get("y")); add((Double) landmark72_jsonArray.getJSONObject(70).get("x"));}});return landmark;}

其中的Landmark 类型 是个实体类,实体类的源码请参考本文末~ 
解析完json就可以分析数据了,当时在此处遇到了个难点,很是想不通的一个逻辑,于是就去各大java群里面进行提问,功夫不负有心人,遇到一大佬给我话了个图解决了我当时的难点,(这边要特别鸣谢一下大佬!!)图:

光看图大家肯定看不明白,我在这里先解释一下吧,我当时的思路是:前台通过定时器,每1s进行提交一次图像数据,然后在后台进行比较上一次执行结果和下一次执行结果的值,然后想不通这里面的业务是什么样子的,于是就有了上面的这张图。

第三、分析数据:

张嘴:通过json获取嘴中心的点和上边、下边的位置,张嘴和闭嘴是有差别的,差别如下(解析的json数据):

嘴巴分析:----闭着嘴巴:第一次的上嘴唇:361.1332397
第一次的嘴唇中心:378.8190308
第一次的下嘴唇:382.1697388上中:17
下中:4第一次的上嘴唇:390.951355
第一次的嘴唇中心:409.0862122
第一次的下嘴唇:414.6711731上中:19
下中:5第一次的上嘴唇:402.4402466
第一次的嘴唇中心:417.4428406
第一次的下嘴唇:419.6887207上中:15
下中:2第一次的上嘴唇:403.1029358
第一次的嘴唇中心:419.4420166
第一次的下嘴唇:424.0343018上中:16
下中:5第一次的上嘴唇:445.7279663
第一次的嘴唇中心:455.8665161
第一次的下嘴唇:457.3482971上中:10
下中:2第二次的上嘴唇:454.5872192
第二次的嘴唇中心:462.1132812
第二次的下嘴唇:463.1278381上中:8
下中:1

上中:嘴唇上边与嘴唇中心的距离 
下中:嘴唇下边与嘴唇中心的距离

眨眼:正常人的眼镜都是有两只(左眼和右眼),所以这边我们比较的时候就比张嘴验证麻烦了,思路还是和张嘴的思路是一样的,下面的返回解析的分析数据:

***********************************************************************************闭着眼的左眼上边:250.549469
闭着眼的左眼中间:252.7034607
闭着眼的左眼下边:258.3751831
闭着眼的左眼上边与中间的值:2.153991700000006
闭着眼的左眼下边与中间的值:5.6717224000000215
闭着眼的右眼上边:248.886261
闭着眼的右眼中间:251.9490204
闭着眼的右眼下边:257.2275391
闭着眼的右眼上边与中间的值:3.0627594000000045
闭着眼的右眼下边与中间的值:5.2785187000000064闭着眼的左眼上边:236.7052612
闭着眼的左眼中间:239.7859192
闭着眼的左眼下边:245.471283
闭着眼的左眼上边与中间的值:3.0806579999999997
闭着眼的左眼下边与中间的值:5.685363800000005
闭着眼的右眼上边:234.837738
闭着眼的右眼中间:238.6846619
闭着眼的右眼下边:244.2976685
闭着眼的右眼上边与中间的值:3.8469239000000073
闭着眼的右眼下边与中间的值:5.613006599999977闭着眼的左眼上边:245.0596619
闭着眼的左眼中间:246.9369202
闭着眼的左眼下边:252.2763367
闭着眼的左眼上边与中间的值:1.877258299999994
闭着眼的左眼下边与中间的值:5.339416499999999
闭着眼的右眼上边:241.4249573
闭着眼的右眼中间:244.3227234
闭着眼的右眼下边:249.2035217
闭着眼的右眼上边与中间的值:2.8977661000000126
闭着眼的右眼下边与中间的值:4.880798300000009*********************************************************************************
闭着眼的左眼上边与中间的值:2.843383799999998
闭着眼的左眼下边与中间的值:6.379211400000003
闭着眼的右眼上边与中间的值:3.6415863
闭着眼的右眼下边与中间的值:5.569457999999997
闭着眼的左眼上边与中间的值:7.1395263
闭着眼的左眼下边与中间的值:8.606811599999986
闭着眼的右眼上边与中间的值:7.101028499999984
闭着眼的右眼下边与中间的值:7.526168800000022
闭着眼的左眼上边与中间的值:4.141037000000011
闭着眼的左眼下边与中间的值:7.363510200000007
闭着眼的右眼上边与中间的值:4.587234499999994
闭着眼的右眼下边与中间的值:6.540771500000034
闭着眼的左眼上边与中间的值:2.4197997999999643
闭着眼的左眼下边与中间的值:5.460693300000003
闭着眼的右眼上边与中间的值:2.9811705999999845
闭着眼的右眼下边与中间的值:4.65585329999999

上面数据一大推,大家看出来个123就行了。 
验证成功返回前台就行了。


关键代码贴上来: 
张张嘴的验证:

/*** * @Description: 该方法的主要作用:张张嘴验证* @Title: face_jiance* @param  @param img* @param  @param response* @param  @param request 设定文件  * @return  返回类型:void   * @throws* 个人博客:https://blog.csdn.net/qq_34137397*/private void face_mouse(String img, HttpServletResponse response,HttpServletRequest request) {        /*if (dataMap.get(1) == null) {// 第一次请求landmark = face_jiance(img);System.out.println("第一次的上嘴唇:"+landmark.getMouse__top().get(0));System.out.println("第一次的嘴唇中心:"+landmark.getMouse_zhongxin().get(0));System.out.println("第一次的下嘴唇:"+landmark.getMouse__bottom().get(0));dataMap.put(1, landmark);} else {*/// 不是第一次请求Landmark landmark_next = face_jiance(img);            // 和前一次的数据进行比较//Landmark landmark_pre = (Landmark) dataMap.get(1);// 嘴唇上面的位置相对于中心点对比PrintWriter writer;            if ((landmark_next.getMouse_zhongxin().get(0) - landmark_next.getMouse__top().get(0)) > 40&&(landmark_next.getMouse__bottom().get(0) - landmark_next.getMouse_zhongxin().get(0)) > 30) {                    try {writer = response.getWriter();writer.print("1");} catch (IOException e) {                        // TODO 异常执行块!e.printStackTrace();}}else{                try {writer = response.getWriter();writer.print("0");} catch (IOException e) {                    // TODO 异常执行块!e.printStackTrace();}}            //dataMap.put(1,landmark_next);         //放进去  方便下次进行比较}    /*}*/

眨眨眼的验证代码:

/*** * @Description: 该方法的主要作用:眨眼对比* @Title: face_eye* @param  @param img* @param  @param response* @param  @param request 设定文件  * @return  返回类型:void   * @throws* 个人博客:https://blog.csdn.net/qq_34137397*/private void face_eye(String img, HttpServletResponse response,HttpServletRequest request) {Landmark landmark_next = face_jiance(img);System.out.println("闭着眼的左眼上边与中间的值:"+((landmark_next.getLeft_eye_zhongxin().get(0))-(landmark_next.getLeft_eye_top().get(0))));System.out.println("闭着眼的左眼下边与中间的值:"+((landmark_next.getLeft_eye_bottom().get(0))-(landmark_next.getLeft_eye_zhongxin().get(0))));System.out.println("闭着眼的右眼上边与中间的值:"+((landmark_next.getRight_eye_zhongxin().get(0))-(landmark_next.getRight_eye_top().get(0))));System.out.println("闭着眼的右眼下边与中间的值:"+((landmark_next.getRight_eye_bottom().get(0))-(landmark_next.getRight_eye_zhongxin().get(0))));System.out.println("__________________________________________________");PrintWriter writer;if ((landmark_next.getLeft_eye_zhongxin().get(0))- (landmark_next.getLeft_eye_top().get(0)) < 6&& (landmark_next.getRight_eye_zhongxin().get(0))- (landmark_next.getRight_eye_top().get(0)) < 6) {System.out.println("进来了上边验证成功");// 继续判断下边的if ((landmark_next.getLeft_eye_bottom().get(0))- (landmark_next.getLeft_eye_zhongxin().get(0)) < 6.6&& (landmark_next.getRight_eye_bottom().get(0))- (landmark_next.getRight_eye_zhongxin().get(0)) < 6.6) {System.out.println("进来了下边验证成功");try {writer = response.getWriter();writer.print("1");} catch (IOException e) {// TODO 异常执行块!e.printStackTrace();}} else {try {writer = response.getWriter();writer.print("0");} catch (IOException e) {// TODO 异常执行块!e.printStackTrace();}}}}

最后上传源码【请点击阅读原文获取源码】:

感谢您抽出  · 来阅读此文

更多精彩请点击【阅读原文】哦

↓↓↓

青鸟IT汇,一个专注于IT技术和互联网资讯的公众号欢迎大家的关注!!!

人脸识别活体检测之张张嘴和眨眨眼相关推荐

  1. 人脸识别活体检测之张张嘴和眨眨眼——readme

    人脸检测返回参数详情 ----------------------------------------------------------------------------------------- ...

  2. 人脸识别活体检测之张张嘴和眨眨眼——Json_Parsing

    /** * @Title: Json_Parsing.java * @Package org.util * @Description: TODO该方法的主要作用: * @author A18ccms ...

  3. 人脸识别活体检测之张张嘴和眨眨眼——Landmark

    /** * @Title: Landmark.java * @Package org.entity * @Description: TODO该方法的主要作用: * @author A18ccms A1 ...

  4. 使用 face++ API 实现人脸识别,刷脸登陆和活体检测(张张嘴,眨眨眼)

    简述 最近需要用到人脸识别功能,于是就上网找了下人脸识别的 API,最后找到了 face++ 于是就想着用 face++ 的 api 来做一个刷脸登陆的 Demo 实现思路 注册时,前台通过浏览器调用 ...

  5. dlib实现人脸识别+活体检测

    目录: 一:dlib的shape_predictor_68_face_landmarks模型 二.眨眼检测 三.张口检测 四.眨眼检测+张口检测 五.人脸识别 六.人脸识别+活体检测 七.人脸识别破解 ...

  6. 人脸识别--活体检测(眨眼检测)

    人脸识别在现在很多的项目中都有应用,最常见的就属此次315曝光的支付宝刷脸登录,当然支付宝也出来做了澄清,我们还是需要相信科技的.支付宝的刷脸可谓是相当成熟了.下面我们来简单的分析一下支付宝的刷脸登录 ...

  7. Android开发之虹软人脸识别活体检测基本步骤

    首先,我简单说下虹软的人脸识别基本步骤: 1.你的设置好设置视频模式方向用于人脸检测 有如下几个可设置方向 //设置视频模式全方向人脸检测ConfigUtil.setFtOrient(this, Fa ...

  8. 微信公众号人脸识别|活体检测SDK|人证比对API

    一.概述 人脸识别特指利用分析比较人脸视觉特征信息进行身份鉴别的计算机技术.人脸识别是一项热门的计算机技术研究领域,可以将人脸明暗侦测,自动调整动态曝光补偿,人脸追踪侦测,自动调整影像放大:它属于生物 ...

  9. Android开发之虹软人脸识别活体检测SDK包Bitmap转NV21方法

    /** * Bitmap 转化为 ARGB 数据,再转化为 NV21 数据 * * @param src 传入的 Bitmap,格式为 Bitmap.Config.ARGB_8888 * @param ...

最新文章

  1. Android--UI之ImageView
  2. aspx文件、aspx.cs文件、aspx.designer.cs文件之讲解
  3. 使用hexo yeele主题搭建个人博客
  4. 网络计算机无法访问 请检查,局域网电脑无法访问,请检查来宾访问帐号是否开通...
  5. redis 类型、方法
  6. OwlCarousel.js 帮助API
  7. 可重入性和线程安全性
  8. Hadoop 1.x和Hadoop 2.x,Hadoop 1.x局限性和Hadoop 2.x YARN优点之间的区别
  9. JS 变量的数据类型 运算符
  10. Solved - Safari keeps forcing HTTPS on localhost
  11. 你好,布灵!高瓴人工智能学院首个AI小精灵诞生
  12. Extjs处理客户复制三位一撇到numberfield里面
  13. 运维工程师都在做什么?
  14. 《数据结构与算法基础 严蔚敏版》第三章 堆栈与队列
  15. 主持人大赛计算机专业,计算机系主持人大赛简报
  16. 通过 Terracotta实现基于Tomcat的Web应用集群
  17. 山东大学 计算机人工智能2019级 认知科学与类脑计算 期末考试
  18. 【引用】免费论文检测 系统 软件 论文免费检测 论文抄袭检测大师 万方数据论文相似性检测系统 万方论文检测...
  19. Python小记 Faker整理
  20. SEA创建、网卡聚合

热门文章

  1. 2023轻薄投影仪首选:极米Z6X Pro入手超值!
  2. [android] app运行在夜神模拟器上
  3. cocos-Lua FairyGUI 之 列表(九)
  4. 微信扫一扫 扫普通链接二维码打开微信小程序
  5. 【BasicNet系列:六】MobileNet 论文 v1 v2 笔记解读 + pytorch代码分析
  6. //苏嵌//张朋//2018.07.11
  7. Hive-beeline启动脚本
  8. MATLAB符号变量的创建和简单运算
  9. Getting Started and Beyond|云原生应用负载均衡选型指南
  10. java计算机毕业设计学生用品采购系统源码+数据库+系统+lw文档+部署