工具系列 | H5如何实现人脸识别

背景

人脸识别技术在当下已经十分成熟,但主要在移动端和专有设备应用上较为普及,而在Web端并不多见,本着学习的目的从零实现web端的人脸登录功能。

视频流

使用navigator.getUserMedia方法在浏览器中获取视频流+音频流(通过摄像头麦克风),将来可以用于获取任意数据流,比如光盘和传感器。

识别工具

百度人脸识别库

1、分析图片中人脸的遮挡度、模糊度、光照强度、姿态角度、完整度、大小等特征,基于输出的符合质量标准的图片,返回准确的相似度评分


2、比对图片中两张人脸的相似度,并返回相似度分值


3、支持生活照、证件照、身份证芯片照、带网纹照4种图片类型的人脸对比


4、分析单张图片中人像的破绽(摩尔纹、成像畸形等),判断图片中目标对象否为真人,确保比对效果真实可靠

face_recognition

被称为世界上最简单的人脸识别库(使用确实超简单)。你可以通过Python引用或者命令行的形式使用它,来管理和识别人脸。

该软件包使用dlib中最先进的人脸识别深度学习算法,使得识别准确率在《Labled Faces in the world》测试基准下达到了99.38%。

它同时提供了一个叫face_recognition的命令行工具,以便你可以用命令行对一个文件夹中的图片进行识别操作。

总体流程

  1. 启动web服务,使用face_recognition将基础库图片进行建模,将建模结果(识别到的人脸在图片中的位置和人脸特征)加载到内存。
  2. 前端通过h5页面的getUserMedia方法调用摄像头获取视频流。
  3. 通过canvas抓取一帧视频转化为图片(base64),使用http或websocket发送到后台。
  4. 后台接受base64参数并转化为图片保存。
  5. 调用face_recognition.locations和face_recognition.face_encodings进行图片建模。
  6. 调用face_recognition.compare_faces将图片建模结果与基础库结果比对。
  7. 根据定义的比对阈值(被称为容忍度,一般为0.6)返回比对结果,如果阈值小于该值,判断是该用户,认定允许登录,返回系统界面。否则返回人脸识别失败的信息。

流程图

图片

时序图

图片

参考案例

前段代码

<div class="layui-container">
    <div class="blog-main">
        <!-- 左边区域 -->
        <div id="support"></div>
        <div class="div-a" id="contentHolder">
            <video id="video" width="100%" height="60%" autoplay></video>
            <canvas hidden="hidden" id="canvas" width="520" height="250"></canvas>
        </div>
        <div class="div-b">
            <!-- <input type="button" id="snap" style="width:100px;height:35px;" value="拍 照" />
            <input type="button" onclick="CatchCode();" style="width:100px;height:35px;" value="上传服务器" /> -->

            <h3>检测实时数据</h3>
            <span>年龄:</span><span id="age"></span><br />
            <span>颜值:</span><span id="beauty"></span><br />
            <span>性别:</span><span id="gender"></span><br />
            <span>人种:</span><span id="race"></span><br />
            <span>是否戴眼镜:</span><span id="glasses"></span><br />
            <span>表情:</span><span id="expression"></span><br />
        </div>
    </div>
</div>

<script>

    //判断浏览器是否支持HTML5 Canvas
    window.onload = function () {
        try {
            //动态创建一个canvas元 ,并获取他2Dcontext。如果出现异常则表示不支持 document.createElement("canvas").getContext("2d");
            document.getElementById("support").innerHTML = "浏览器支持HTML5 CANVAS";
        }
        catch (e) {
            document.getElementByIdx("support").innerHTML = "浏览器不支持HTML5 CANVAS";
        }
    };

    var timer = null;
    //这段代 主要是获取摄像头的视频流并显示在Video 签中
    window.addEventListener("DOMContentLoaded", function () {
        var canvas = document.getElementById("canvas"),
            context = canvas.getContext("2d"),
            video = document.getElementById("video"),
            // videoObj = { "video": true },
            //调用用户媒体设备,访问摄像头
            mediaConstraints = {
                audio: false,
                video: {
                    width: { ideal: 1280 },
                    height: { ideal: 720 },
                    frameRate: {
                        ideal: 10,
                        max: 15
                    },
                    facingMode: "environment"
                }
            };
        errBack = function (error) {
            console.log("Video capture error: ", error.code);
        };
        //拍照按钮
        //         $("#snap").click(function () {
        //             context.drawImage(video, 0, 0, 330, 250);
        //         })

        //拍照每秒一次
        timer = setInterval(function () {
            context.drawImage(video, 0, 0, 330, 250)
            CatchCode();
        }, 3000);

        //navigator.getUserMedia这个写法在Opera中好像是navigator.getUserMedianow
        //更新兼容火狐浏览器
        if (navigator.mediaDevices.getUserMedia || navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia) {
            navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
            navigator.getUserMedia(mediaConstraints, function (stream) {
                video.srcObject = stream;
                video.play();
            }, errBack);
        }
    }, false);

    /**
    * Base64 数据处理
    */
    function dataURItoBlob(base64Data) {
        var byteString;
        if (base64Data.split(',')[0].indexOf('base64') >= 0)
            byteString = atob(base64Data.split(',')[1]);
        else
            byteString = unescape(base64Data.split(',')[1]);
        var mimeString = base64Data.split(',')[0].split(':')[1].split(';')[0];
        var ia = new Uint8Array(byteString.length);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }
        return new Blob([ia], { type: mimeString });
    }

    /**
    * 上传服务器
    */
    function CatchCode() {
        var canvans = document.getElementById("canvas");
        //获取浏览器页面的画布对象
        //以下开始编 数据
        var imageBase64 = canvans.toDataURL();
        var blob = dataURItoBlob(imageBase64);
        var fd = new FormData(document.forms[0]);
        fd.append("the_file", blob, 'image.png');
        //将图像转换为base64数据
        $.ajax({
            type: "POST",
            url: "{:url('/index/Index/faceVerifyVideo')}",
            processData: false,     // 必须
            contentType: false,     // 必须
            data: fd,
            datatype: "json",
            success: function (res) {
                console.log(res);
                if (res.code == 0) {
                    // layer.msg(JSON.stringify(res.data.face_list));
                    var jsonObj = res.data.face_list[0];
                    var age = jsonObj.age;
                    var beauty = jsonObj.beauty;
                    var gender = jsonObj.gender;
                    var race = jsonObj.race;
                    var glasses = jsonObj.glasses;
                    var expression = jsonObj.expression

                    $("#age").html(age);
                    $("#beauty").html(beauty);

                    if (gender.type == 'male') {
                        $("#gender").html("男");
                    } else {
                        $("#gender").html("女");
                    }

                    if (race.type == 'yellow') {
                        $("#race").html("黄种人");
                    } else if (race.type == 'white') {
                        $("#race").html("白种人");
                    } else if (race.type == 'black') {
                        $("#race").html("黑种人 ");
                    } else {
                        $("#race").html("阿拉伯人");
                    }

                    if (glasses.type == 'none') {
                        $("#glasses").html("未戴眼镜");
                    } else if (glasses.type == 'common') {
                        $("#glasses").html("戴了普通眼镜");
                    } else {
                        $("#glasses").html("戴了墨镜");
                    }

                    if (expression.type == 'none') {
                        $("#expression").html("不笑");
                    } else if (expression.type == 'smile') {
                        $("#expression").html("微笑");
                    } else {
                        $("#expression").html("大笑");
                    }
                    // layer.alert(res.msg, { icon: 6 });
                    clearInterval(timer);
                } else {
                    layer.msg(res.msg, { icon: 5 });
                }
            },
            error: function () {
                layer.alert('接口异常', { icon: 5 });
            }
        });
    }
</script>

服务端代码

微信公众号回复 百度人脸识别代码 获取

阅读原文

简介:专注互联网技术干货分享。包括Redis、PHP、MySQL、Nginx/Openresty、网关、消息队列、Docker、微服务、代码案例等。欢迎关注微信公众号:开源技术小栈

声明:本文来自“开源技术小栈”,本文链接:https://www.zyxiao.com/p/297663

发表评论

登录后才能评论
网站客服
网站客服
内容投稿 侵权处理
分享本页
返回顶部