美文网首页
还在用密码登录?快来试试离线人脸登录吧

还在用密码登录?快来试试离线人脸登录吧

作者: 爪哇日记 | 来源:发表于2020-04-08 11:42 被阅读0次

    基于虹软的离线人脸识别

    • 注册虹软账号,获取离线SDK
    • 自定义人脸库(保存人脸关键点信息),并添加人脸到人脸库
    • 获取登录客户的人脸
    • 使用SDK解析人脸,获取关键点信息
    • 登录人脸信息 与人脸库比对 比对成功或失败(对应登录成功或失败)

    人脸识别示例:

    • 添加用户(成功后提示,并在数据库插入一条数据)


      在这里插入图片描述
      在这里插入图片描述
    • 查找用户(匹配成功后回填用户信息,可以根据业务跳转登录)
      在这里插入图片描述

    获取虹软SDK

    先在 虹软官网 登录开发者账号(没有账号先注册后再登录)


    创建人脸识别应用

    在这里插入图片描述
    创建SDK(以windows为例)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    SKD包文件内容
    在这里插入图片描述

    人脸识别工具类   创建FaceEngine 引擎时要指定依赖文件路径(为sdk压缩包中 libs文件夹下的dll文件路径)

    package com.face.facetest.utils;
    
    import com.arcsoft.face.*;
    import com.arcsoft.face.enums.DetectMode;
    import com.arcsoft.face.enums.DetectOrient;
    import com.arcsoft.face.enums.ErrorInfo;
    import com.arcsoft.face.toolkit.ImageInfo;
    import lombok.Data;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.PostConstruct;
    import javax.imageio.ImageIO;
    import javax.imageio.stream.FileImageOutputStream;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    import static com.arcsoft.face.toolkit.ImageFactory.getRGBData;
    
    /**
     * @Auther: zs
     * @Date: 2020/4/7 15:51
     * @Description:
     */
    @Data
    @Component
    public class FaceUtils {
    
        @Value("${face.appId}")
        private String appId1;
        @Value("${face.sdkKey}")
        private String sdkKey1;
    
        public static String appId;
        public static String sdkKey;
    
        @PostConstruct
        public void init(){
            appId = this.appId1;
            sdkKey = this.sdkKey1;
        }
    
        //特征比对
        public static float compare(FaceEngine faceEngine,byte[] sources,byte[] target){
            FaceFeature targetFaceFeature = new FaceFeature();
            targetFaceFeature.setFeatureData(target);
            FaceFeature sourceFaceFeature = new FaceFeature();
            sourceFaceFeature.setFeatureData(sources);
            FaceSimilar faceSimilar = new FaceSimilar();
            int errorCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
            return faceSimilar.getScore();
        }
    
        //特征
        public static byte[] feature(FaceEngine faceEngine,byte[] bytes,FaceInfo faceInfo){
            ImageInfo imageInfo = getRGBData(bytes);
            //特征提取
            FaceFeature faceFeature = new FaceFeature();
            int errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfo, faceFeature);
            System.out.println("特征值大小:" + faceFeature.getFeatureData().length);
            return faceFeature.getFeatureData();
        }
    
        //获取人脸位置
        public static List<FaceInfo> detectFaces(FaceEngine faceEngine,byte[] bytes){
            //人脸检测
            ImageInfo imageInfo = getRGBData(bytes);
            List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
            int errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
            return faceInfoList;
        }
    
    
        public static FaceEngine getFaceEngine(){
    
            /*
            * 此路径为sdk压缩包中 libs文件夹下的dll文件路径
            * */
            FaceEngine faceEngine = new FaceEngine("C:\\Users\\zs\\Desktop\\ArcSoft\\arcsoft_lib");
            //激活引擎
            int errorCode = faceEngine.activeOnline(appId, sdkKey);
    
            if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
                System.out.println("引擎激活失败");
            }
    
            ActiveFileInfo activeFileInfo=new ActiveFileInfo();
            errorCode = faceEngine.getActiveFileInfo(activeFileInfo);
            if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
                System.out.println("获取激活文件信息失败");
            }
    
            //引擎配置
            EngineConfiguration engineConfiguration = new EngineConfiguration();
            engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
            engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
            engineConfiguration.setDetectFaceMaxNum(10);
            engineConfiguration.setDetectFaceScaleVal(16);
            //功能配置
            FunctionConfiguration functionConfiguration = new FunctionConfiguration();
            functionConfiguration.setSupportAge(true);
            functionConfiguration.setSupportFace3dAngle(true);
            functionConfiguration.setSupportFaceDetect(true);
            functionConfiguration.setSupportFaceRecognition(true);
            functionConfiguration.setSupportGender(true);
            functionConfiguration.setSupportLiveness(true);
            functionConfiguration.setSupportIRLiveness(true);
            engineConfiguration.setFunctionConfiguration(functionConfiguration);
    
    
            //初始化引擎
            errorCode = faceEngine.init(engineConfiguration);
    
            if (errorCode != ErrorInfo.MOK.getValue()) {
                System.out.println("初始化引擎失败");
            }
            return faceEngine;
        }
    }
    

    注意:人脸识别的jar包需要添加依赖后才可正常使用,否则会报异常。springboot项目jar报启动时 可在:File->Project Structure->Modular 下添加依赖

    在这里插入图片描述
    数据库
    在这里插入图片描述
    保存人脸信息-页面
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/css/common.css" media="all">
    </head>
    <body class="align-center">
    
        <h1 style="margin-top: 50px">添加用户信息</h1>
        <br>
        <div class="faceDiv">
            <video id="video"></video>
            <canvas id="canvas" style="display: none;"></canvas>
        </div>
        <br/><br/><br/>
        用户名:<input id="name" />
        <br/><br/><br/>
        <button id="saveUser">保存</button>
    </body>
    <script src="/js/jquery-3.4.1.min.js" charset="utf-8"></script>
    <script src="/js/face.js" charset="utf-8"></script>
    <script>
        openUserMedia();
    
        $("#saveUser").click(function () {
            var name = $("#name").val();
            if(name){
                var img = getFace();
                $.ajax({
                    type:"post",
                    url:"/addUser",
                    data:{
                        "faceStr":img,
                        "name":name
                    },
                    success:function (rst) {
                        alert(rst.msg)
                    },
                    error:function () {
                        alert("连接服务器失败")
                    }
                })
            }else{
                alert("姓名不能为空")
            }
    
    
        })
    </script>
    </html>
    
    在这里插入图片描述
    查找人脸信息-页面
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/css/common.css" media="all">
    </head>
    <body class="align-center">
    
        <h1 style="margin-top: 50px">查找用户信息</h1>
        <br>
        <div class="faceDiv">
            <video id="video"></video>
            <canvas id="canvas" style="display: none;"></canvas>
        </div>
        <br/><br/><br/>
        用户信息:<span id="userInfo"></span>
        <br/><br/><br/>
        <button id="searchUser">查找</button>
    </body>
    <script src="/js/jquery-3.4.1.min.js" charset="utf-8"></script>
    <script src="/js/face.js" charset="utf-8"></script>
    <script>
        openUserMedia();
    
        $("#searchUser").click(function () {
            var img = getFace();
            $.ajax({
                type:"post",
                url:"/searchUser",
                data:{
                    "faceStr":img
                },
                success:function (rst) {
                    $("#userInfo").html(rst.msg)
                },
                error:function () {
                    alert("连接服务器失败")
                }
            })
    
        })
    </script>
    </html>
    
    在这里插入图片描述
    页面获取摄像头JS(页面引用的face.js)
    
    //成功回调函数
    var video = document.getElementById("video");
    var canvas = document.getElementById("canvas");
    var context = canvas.getContext("2d");
    var mediaStreamTrack=null;
    function success(stream){
        //兼容webkit核心浏览器
        //将视频流转化为video的源
        mediaStreamTrack=stream;
        try {
            // video.src = CompatibleURL.createObjectURL(stream);
            video.srcObject=stream;
        }catch (e) {
            console.log("访问用户媒体设备失败:",error.name,error.message);
        }
    
        video.play();//播放视频
    }
    //错误回调函数
    function error(error) {
        console.log('访问用户媒体失败:',error.name,error.message);
    }
    function getUserMediaToPhoto(constraints,success,error) {
        if(navigator.mediaDevices.getUserMedia){
            //最新标准API
            navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
        }else if (navigator.webkitGetUserMedia) {
            //webkit核心浏览器
            navigator.webkitGetUserMedia(constraints,success,error);
        }else if(navigator.mozGetUserMedia){
            //firefox浏览器
            navigator.mozGetUserMedia(constraints,success,error);
        }else if(navigator.getUserMedia){
            //旧版API
            navigator.getUserMedia(constraints,success,error);
        }
    }
    //获取图片
    function getFace() {
        context.drawImage(video,0,0,300,150);
        this.img=canvas.toDataURL('image/jpg')
        //获取完整的base64编码
        this.img=img.split(',')[1];
        return this.img;
    }
    //打开摄像头
    function openUserMedia() {
        if(navigator.mediaDevices.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia){
            getUserMediaToPhoto({video:{width:300,height:300,facingMode: "user"}},success,error);
        }else{
            alert('你的浏览器不支持访问用户媒体设备');
        }
    }
    //关闭摄像头
    function  offUserMedia() {
        if(mediaStreamTrack!=null)
            mediaStreamTrack.getTracks()[0].stop();
    }
    
    
    
    
    

    后台Controller

    package com.face.facetest.controller;
    
    import com.arcsoft.face.FaceEngine;
    import com.arcsoft.face.FaceInfo;
    import com.face.facetest.service.FaceInfoServiceImpl;
    import com.face.facetest.utils.FaceUtils;
    import com.face.facetest.utils.ImageUtils;
    import com.face.facetest.vo.FaceVo;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.util.StringUtils;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.HashMap;
    import java.util.List;
    
    /**
     * @Auther: zs
     * @Date: 2020/4/7 15:47
     * @Description:
     */
    @RestController
    public class IndexController {
        @Autowired
        private FaceInfoServiceImpl faceInfoService;
    
        @RequestMapping("/addUser")
        public Object addUser(HttpServletRequest request, FaceVo faceVo){
            HashMap<Object, Object> result = new HashMap<>();
            result.put("msg","异常");
            if(faceVo.getFaceStr() != null && faceVo.getName() != null){
                byte[] bytes = ImageUtils.base64ToByte(faceVo.getFaceStr());
                FaceEngine faceEngine = FaceUtils.getFaceEngine();
                List<FaceInfo> faceInfos = FaceUtils.detectFaces(faceEngine, bytes);
                if(faceInfos != null && faceInfos.size() > 0){
                    byte[] feature = FaceUtils.feature(faceEngine, bytes, faceInfos.get(0));
                    com.face.facetest.entry.FaceInfo faceInfo = new com.face.facetest.entry.FaceInfo();
                    faceInfo.setName(faceVo.getName());
                    faceInfo.setFaceData(feature);
                    boolean save = faceInfoService.save(faceInfo);
                    if(save){
                        result.put("msg","添加成功");
                    }
                }
                faceEngine.unInit();
            }
            return result;
        }
    
    
        @RequestMapping("/searchUser")
        public Object searchUser(HttpServletRequest request, FaceVo faceVo){
            HashMap<Object, Object> result = new HashMap<>();
            result.put("msg","异常");
            if(faceVo.getFaceStr() != null){
                byte[] bytes = ImageUtils.base64ToByte(faceVo.getFaceStr());
                FaceEngine faceEngine = FaceUtils.getFaceEngine();
                List<FaceInfo> faceInfos = FaceUtils.detectFaces(faceEngine, bytes);
                if(faceInfos != null && faceInfos.size() > 0){
                    byte[] feature = FaceUtils.feature(faceEngine, bytes, faceInfos.get(0));
                    if(feature != null){
                        List<com.face.facetest.entry.FaceInfo> list = faceInfoService.list();
                        if(list != null){
                            for (com.face.facetest.entry.FaceInfo faceInfo : list) {
                                if(faceInfo.getFaceData() != null){
                                    float compare = FaceUtils.compare(faceEngine, feature, faceInfo.getFaceData());
                                    if(compare >= 0.8){
                                        result.put("msg",faceInfo.getName());
                                    }
                                }
                            }
                        }
                    }
    
                }
                faceEngine.unInit();
            }
            return result;
        }
    }
    
    

    流程总结:

    人脸识别流程(添加用户):

    • 页面获取头像
    • 后台获取头像,SDK解析获取关键点信息
    • 保存数据库

    人脸识别流程(查找用户):

    • 获取头像信息
    • 后台获取头像,SDK解析获取关键点信息
    • 获取头像库的信息,比对相似值(官方推荐获取相似值大于0.8的),并获取用户唯一标识(此处名称为唯一标识,可根据业务自行指定)
    • 根据唯一标示获取用户信息
    • 根据用户信息按正常的登录流程走就可以了

    项目下载地址:https://github.com/15225845996/face-test.git

    搜索公众号:【爪哇日记】关注最新文章

    在这里插入图片描述

    相关文章

      网友评论

          本文标题:还在用密码登录?快来试试离线人脸登录吧

          本文链接:https://www.haomeiwen.com/subject/rezznqtx.html