基于百度AI+jquery-webcam+servlet实现人脸识别登录,兼容各主流浏览器

1、注册百度AI账号,获取到AI开发资格

     详情参见个人博客:你的第一个人脸识别demo(http://www.cnblogs.com/guo-eric/p/8109411.html

2、环境准备

首先按照第一步说明将百度的AI类文件和用到的三方类文件下载到本地,需要的文件有:

     

然后从jquery-webcam官网下载操作摄像头的插件:

下载地址:https://www.xarg.org/project/jquery-webcam-plugin/

下载后解压文件:

最后将jquery的js文件引入,我这里用的是1.8.3:如上面截图所示

3、前端页面开发:采用jsp页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta charset="utf-8">
<title>jQuery-webcam-master</title>
<script src="js/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="js/jquery.webcam.min.js"></script>
<style type="text/css">
#webcam {
    border: 1px solid #666666;
     320px;
    height: 240px;
}

#photos {
    border: 1px solid #666666;
     320px;
    height: 240px;
}

.btn {
     320px;
    height: auto;
    margin: 5px 0px;
}

.btn input[type=button] {
     150px;
    height: 50px;
    line-height: 50px;
    margin: 3px;
}
</style>

</head>
<body>
    <input type="text" id="uid" value="">
    <div id="webcam"></div>

    <div class="btn">
        <input type="button" value="注册" id="regBtn" onclick="action('reg');" /> 
        <input type="button" value="登录" id="saveBtn" onclick="action('login');" />
    </div>

    <div id="photos">

        <img src="" id="img">

    </div>
</body>


<script type="text/javascript">
    $(document).ready(function() {
        var pos = 0, ctx = null, saveCB, image = [];
        //创建画布指定宽度和高度
        var canvas = document.createElement("canvas");
        canvas.setAttribute('width', 320);
        canvas.setAttribute('height', 240);
        //如果画布成功创建
        if (canvas.toDataURL) {
            //设置画布为2d,未来可能支持3d
            ctx = canvas.getContext("2d");
            //截图320*240,即整个画布作为有效区(cutx?)
            image = ctx.getImageData(0, 0, 320, 240);

            saveCB = function(data) {
                //把data切割为数组
                var col = data.split(";");
                var img = image;
                //绘制图像(这里不是很理解算法)
                //参数data  只是每行的数据  ,例如320*240 大小的照片,一张完整的照片下来需要240个data,每个data有320个rgb
                for (var i = 0; i < 320; i++) {
                    //转换为十进制
                    var tmp = parseInt(col[i]);
                    img.data[pos + 0] = (tmp >> 16) & 0xff;
                    img.data[pos + 1] = (tmp >> 8) & 0xff;
                    img.data[pos + 2] = tmp & 0xff;
                    img.data[pos + 3] = 0xff;
                    pos += 4;
                }
                //当绘制320*240像素的图片时发给后端php
                if (pos >= 4 * 320 * 240) {
                    //把图像放到画布上,输出为png格式
                    ctx.putImageData(img, 0, 0);
                    //alert('图片保存成功');
                    $.ajax({
                        url : 'upload.do?method='+method+'&uid='+$('#uid').val(),
                        type : "POST",
                        dataType : 'json',
                        async : false,
                        data : {image : canvas.toDataURL("image/png")},
                        success : function(data) {    
                            alert(data.flag+'---'+data.message);
                            var msg = data.message;
                            if (msg != "success") {
                                resultflag=false;
                            }
                        },
                        error : function(error) {
                            tip('访问数据异常', '异常提示');
                            return true;
                        }
                    });
                /*     $.post("upload.do", {
                        type : "data",
                        image : canvas.toDataURL("image/png"),
                        function(data,status){
                            alert("Data: " + data + "
Status: " + status);
                          }
                    }); */
                    pos = 0;
                }
            };

        } else {
            saveCB = function(data) {
                //把数据一点点的放入image[]
                image.push(data);
                pos += 4 * 320;
                if (pos >= 4 * 320 * 240) {
                    $.post("upload.do", {
                        type : "pixel",
                        image : image.join('|')
                    });
                    pos = 0;
                }
            };
        }

        //                /**
        //                 * 获取canvas画布的内容 getImageData
        //                 * 内容放回到canvas画布 putImageData
        //                 * 获取ImgData的每一个像素 ImgData.data
        //                 * getImageData(起始点的横坐标, 起始点的纵坐标, 获取的宽度, 获取的高度)
        //                 * putImageData(绘制点的横坐标, 绘制点点纵坐标, imgData的起始点横坐标, imgData的起始点纵坐标, 宽度, 高度)
        //                 */
        $("#webcam").webcam({
            width : 320,
            height : 240,
            mode : "callback",
            swffile : "js/jscam_canvas_only.swf",
            onTick : function(remain) {

                if (0 == remain) {
                    jQuery("#status").text("Cheese!");
                } else {
                    jQuery("#status").text(remain + " seconds remaining...");
                }
            },
            onSave : saveCB,
            onCapture : function() {
                webcam.save();
            },

            debug : function(type, string) {
                console.log(type + ": " + string);
            }
        });
        
        
    });

    //拍照
    //var iCount = setInterval(action,10000);//循环执行
    //var i = 1;
    var method = 'login';
    function action(action) {
            var uid = $('#uid').val();
            if('' == uid){
                alert('uid不能为空');
                return ;
            }
            if(action != null){
                method = action;
            }
            /* if(i == 1){
                clearInterval(iCount);
            } */
            webcam.capture();
    }
</script>

</script>
</html>

4、servlet接收传经来的base64编码的图片文件,并进行登录和注册的处理

package com.hengyunsoft.face.login;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONObject;

import sun.misc.BASE64Decoder;

import com.baidu.aip.face.AipFace;
import com.hengyunsoft.face.aip.FaceManage;

/**
 * Servlet implementation class UploadFile
 */
@WebServlet("/upload.do")
public class Login extends HttpServlet {
    private static final long serialVersionUID = 1L;
    //设置APPID/AK/SK
    public static final String APP_ID = "10580034";
    public static final String API_KEY = "CUEBLydMIEhyHXGgjuBLMCDx";
    public static final String SECRET_KEY = "xPATdkt3lpn0TiWZyGtfUs1rYrN5HgI6";
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public Login() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            uploadPhoto(request, response);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }

    /**

     * 功能描述:拍照并上传图片

     *

     * @since 2016/5/24

     */

    public void uploadPhoto(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        resp.setContentType("application/text; charset=utf-8");

        String basePath = "upload/" + getDate("yyyyMMdd") + "/";
        String filePath = req.getSession().getServletContext().getRealPath("/") + basePath;
        String fileName = getDate("yyyyMMddHHmmss") + ".png";
        //默认传入的参数带类型等参数:data:image/png;base64,
        PrintWriter out = resp.getWriter();
        JSONObject j = new JSONObject();

        String imgStr = req.getParameter("image");
        String uid = req.getParameter("uid");
        String method = req.getParameter("method");
        if (null != imgStr) {
            imgStr = imgStr.substring(imgStr.indexOf(",") + 1);
        }

       
       //文件上传到服务器
        Boolean flag = GenerateImage(imgStr, filePath, fileName);
        String message = "没有检测到图片";
        if (flag) {
            //拿到base64编码的图片,就可以调用百度的API进行验证
            AipFace client = new AipFace(APP_ID, API_KEY, SECRET_KEY);
            if(method.equals("login")){
                message = login(filePath, fileName, j, uid, client);
            }else if (method.equals("reg")) {
                message = register(filePath, fileName, j, uid, client);
            }
            
        }
        
        j.put("message", message);
        out.write(j.toString());
    }

    /**
     * 登录
     * 
     * @param filePath
     * @param fileName
     * @param j
     * @param uid
     * @param client
     * @return
     */
    private String login(String filePath, String fileName, JSONObject j,
            String uid, AipFace client) {
        String message;
        double matchPercent = FaceManage.verifyUser(client, filePath + fileName,uid);
        if (matchPercent > 90) {
            System.out.println("验证成功,人脸匹配度是:"+matchPercent);
            j.put("flag", true);
            message = "验证成功,人脸匹配度是:"+matchPercent;
        }else{
            System.out.println("验证失败,人脸匹配度是:"+matchPercent);
            j.put("flag", false);
            message = "验证失败,人脸匹配度是:"+matchPercent;
        }
        return message;
    }

    /**
     * 注册
     * 
     * @param filePath
     * @param fileName
     * @param j
     * @param uid
     * @param client
     * @return
     */
    private String register(String filePath, String fileName, JSONObject j,
            String uid, AipFace client) {
        String message;
        int matchPercent = FaceManage.addUser(client, filePath + fileName,uid);
        if (matchPercent == 1) {
            System.out.println("注册成功");
            j.put("flag", true);
            message = "注册成功";
        }else{
            System.out.println("注册失败");
            j.put("flag", false);
            message = "注册失败";
        }
        return message;
    }

    
    

    /**

     * 功能描述:base64字符串转换成图片

     *

     * @since 2016/5/24

     */

    public boolean GenerateImage(String imgStr, String filePath, String fileName) {

        try {
            if (imgStr == null) {
                return false;
            }
            BASE64Decoder decoder = new BASE64Decoder();
            //Base64解码
            byte[] b = decoder.decodeBuffer(imgStr);
            //如果目录不存在,则创建
            File file = new File(filePath);
            if (!file.exists()) {
                file.mkdirs();
            }
            //生成图片

            OutputStream out = new FileOutputStream(filePath + fileName);
            out.write(b);
            out.flush();
            out.close();
            return true;

        } catch (Exception e) {
            System.out.println("生成图片异常:{}"+e.getMessage());
            return false;

        }

    }

    public String getDate(String pattern){
        return new SimpleDateFormat(pattern).format(new Date());
    }
}

其中web.xml的配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>AipFaceSys</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>UploadFile</servlet-name>
    <servlet-class>com.hengyunsoft.UploadFile</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>UploadFile</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

其中servlet中用到的FaceManage等类,都在 博客:你的第一个人脸识别demo((http://www.cnblogs.com/guo-eric/p/8109411.html)中有明确说明,有问题,请联系我,和大家一起学习进步!

 FAQ:

          倘若浏览器报错了:提示webcam.capture is not a function ,这是因为jquery-webcam必须用在项目中,才能够正常使用。

        

  如果IE浏览器中摄像头显示不出来,需要按照以下操作设置:

         1)合理设置浏览器,启用flash的正确方法:

         Internet Explorer,设置,安全,禁用ActiveX筛选(去掉勾)

         2)管理加载项,启用Shockwave Flash Object

原文地址:https://www.cnblogs.com/guo-eric/p/8371861.html