阿里云实现人脸登录(人脸库 OSS)

我自认为不想做curd程序员,但是免不了的会对数据基本原子操作进行处理,项目开发过程中的增删改查少不了的,但是又不甘心于curd下去,所以想要在掌握现有知识的基础上,甚至逼迫自己去学习一些东西,去接触新的技术,足够的深度做不到,最起码广度要有所保证,每天进步一点点。
开篇写的算是自己的程序员生涯的一丢丢想法,言归正传,本篇介绍通过阿里云实现人脸登录功能(百度云原理类似,不过百度云的人脸不是免费的了,so果断阿里云了)。
说实话本篇的说明思路我自己感觉有点乱,只好边写边梳理。。
前提:系统中已经开户成功,user表内有相关用户信息及用户ID(唯一标识)
整体思路:

  • 阿里云开通人脸人体服务,现阶段是免费的,以后说不准哈哈。
    https://homenew.console.aliyun.com在这里插入图片描述
  • 选择人脸数据库管理模块,进行人脸管理,可以新增样本,其实就是将人脸图片与系统内user表ID进行关联与维护。
    在这里插入图片描述
  • 系统PC或移动端摄像头人脸识别,获取人脸base64,调用后端接口,后端接口进行阿里云OSS上传并获得存储路径(后续人脸搜索api方法会要求前端识别人脸图片格式为OSS存储格式,这点有些麻烦),而后调用人脸搜索api从阿里云人脸数据库中搜索是否能匹配到,搜索结果会返回matchList。(人脸搜索可以限制返回最高匹配的几个结果,而不是所有结果)
  • 搜索结果getScore按照匹配分数进行排序,获取分数最高的也就是匹配度最高的,判断分数是否高于0.8(匹配分数按实际情况自己定义)。
  • 根据最高匹配结果获取系统user表内的ID(人脸识别管理库的样本ID已经维护),后续调用系统login接口即可,获取token等操作。
	@ApiOperation(value = "人脸检测接口")
    @PostMapping(value = "/check")
    public Result faceCheck(@RequestBody JSONObject faceJson) {
        String base64Str = faceJson.getString("img");
        String url = aliyunOss.uploadFiles(base64Str);
        if (StringUtils.isBlank(url)) {
            return Result.fail("人脸检测图片失败");
        }
        SearchFaceResponse response = aliFaceRecognize.searchFace(groupId, url);
        if (response==null) {
            return Result.fail("人脸检测失败");
        }
        if (response.getData()==null){
            return Result.fail("未匹配到人脸");
        }
        if (CollectionUtils.isEmpty(response.getData().getMatchList())) {
            return Result.fail("未匹配到人脸");
        }
        List<SearchFaceResponse.Data.MatchListItem.FaceItemsItem> finals = new ArrayList<>();
        List<SearchFaceResponse.Data.MatchListItem> matchList = response.getData().getMatchList();
        for (SearchFaceResponse.Data.MatchListItem matchListItem : matchList) {
            List<SearchFaceResponse.Data.MatchListItem.FaceItemsItem> items = matchListItem.getFaceItems();
            for (SearchFaceResponse.Data.MatchListItem.FaceItemsItem item : items) {
                finals.add(item);
            }
        }
        SearchFaceResponse.Data.MatchListItem.FaceItemsItem maxMaterial = finals.stream().max(Comparator.comparingDouble(SearchFaceResponse.Data.MatchListItem.FaceItemsItem::getScore)).get();
        if(maxMaterial.getScore()<0.8) {
            return Result.fail("人脸匹配精度不准确,请重新识别");
        }
        User user = userService.findById(maxMaterial.getEntityId());
        if (user == null) {
            return Result.fail("未匹配到用户,请开户");
        }
        return Result.success("登录成功!", maxMaterial.getEntityId());
    }

前端使用antdVue实现的,附代码:

<template>
    <div>
        <div class="user-icon">
            <video width="500" height="400" ref="videoDom" id="video" preload autoplay loop muted></video>
            <canvas width="500" height="400" ref="canvasDOM"></canvas>
        </div>

        <div align="center">{{loding}}</div>
        <!--<div @click="initTracker">人脸识别</div>-->
    </div>
</template>

<script>

    require('tracking/build/tracking-min.js')
    require('tracking/build/data/face-min.js')
    export default {
        name: 'FaceLoginAli',
        data() {
            return {
                // 记录拍照到了几次
                count: 0,
                isdetected: '请您保持脸部在画面中央',
                loding: ''
            }
        },
        methods: {
            // 初始化racker
            initTracker(){
                // 启用摄像头,这一个是原生调用摄像头的功能,不写的话有时候谷歌浏览器调用摄像头会失败
                navigator.mediaDevices
                    .getUserMedia({video: true,audio: true})
                    .then(this.getMediaStreamSuccess)
                    .catch(this.getMediaStreamError)

                this.context  = this.canvas.getContext('2d')

                // 初始化tracking参数
                this.tracker = new tracking.ObjectTracker("face");
                this.tracker.setInitialScale(4);
                this.tracker.setStepSize(2);
                this.tracker.setEdgesDensity(0.1);
                this.tracker.on("track", event => {
                    this.onTracked(event);
                });

                // tracking启用摄像头,这里我选择调用原生的摄像头
                // tracking.track(this.video, this.tracker, { camera: true });

                // 如果是读取视频,可以用trackerTask.stop trackerTask.run来暂停、开始视频
                this.trackerTask = tracking.track(this.video, this.tracker);
            },
            // 监听中
            onTracked(event){
                // 判断终止条件, stop是异步的,不返回的话,还会一直截图
                if (this.count >= 21) {
                    this.onStopTracking();
                    return;
                }

                // 画框框
                this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
                event.data.forEach(rect => {
                    this.context.lineWidth = 1;
                    this.context.strokeStyle = "#a64ceb";
                    //'#a64ceb';
                    this.context.strokeRect(rect.x, rect.y, rect.width, rect.height);
                    this.context.font = "11px Helvetica";
                    this.context.fillStyle = "#fff";
                    // 截图

                    if (event.data.length > 0 && this.count <= 20) {
                        if (this.count < 0) {
                            this.count = 0
                        }
                        this.count += 1
                        if (this.count > 20) {
                            this.isdetected = '已检测到人脸,正在识别'
                            this.getPhoto()
                        }
                    } else {
                        this.count -= 1
                        if (this.count < 0){
                            this.isdetected = '请您保持脸部在画面中央'
                        }
                    }


                });
                // 视频中心展示文字
                this.context.fillText(this.isdetected, 200,50);
            },
            // 停止监听
            onStopTracking() {
                this.trackerTask.stop();
                this.video.pause();
                // 关闭摄像头
                this.video.srcObject = null
                window.stream.getTracks().forEach(track => track.stop())

            },
            // 获取人脸照片
            getPhoto(){
                this.isdetected = ''
                this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
                let video = document.getElementById('video')
                this.context.drawImage(video, 0,0, this.canvas.width, this.canvas.height)
                let dataUrl = this.canvas.toDataURL('image/jpeg', 1);
                this.imgbase64 = dataUrl.replace(/^data:image\/\w+;base64,/, "");
                // 开始人脸识别
                this.postFace()
            },
            // 人脸验证
            postFace(){
                this.loding = '正在识别中,请稍后................'
                this.$http.post('admin/face/check',{
                    img: this.imgbase64
                }).then((res)=>{
                    console.log(res)
                    this.loding = ''
                    if(res.success){
                        this.faceLogin(res.data);
                        this.$message.success(res.msg);
                    }else {
                        this.$message.error(res.msg);
                    }
                })
            },
            // 视频流启动
            getMediaStreamSuccess(stream) {
                window.stream = stream
                this.video.srcObject = stream
            },
            // 视频媒体流失败
            getMediaStreamError(error) {
                this.$message.error('视频媒体流获取错误' + error)
            },
            faceLogin(userId) {
                const that = this
                return this.$http.post('/admin/face/login/'+ userId).then(function (res) {
                    if (res.success) {
	                    //这儿写自己登录成功的逻辑
                    }
                });
            }
        },
        mounted() {
            this.video = this.$refs.videoDom
            this.canvas = this.$refs.canvasDOM

            //初始化获取tonken
            this.initTracker();
        },
        destroyed() {

        }
    }
</script>

<style scoped>
    .user-icon {
        position: relative;
        margin: 0 auto;
        margin-top: 50px;
        width: 560px;
        height: 560px;
    }
    .button {
        width: 90vw;
        height: 50px;
        line-height: 50px;
        margin: 0 auto;
        background-color: skyblue;
        color: white;
        text-align: center;
        border-radius: 5px;
        font-size: 16px;
    }
    video, canvas {
        position: absolute;
    }
</style>

写到这儿感觉也就这些东西,我自己是明白整个流程,看这篇文章的不知道是否清楚,如果有疑问可以留言回复。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰红茶不会渴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值