SpringBoot集成百度人脸识别实现登陆注册功能Demo(二)

前言

上一篇SpringBoot集成百度人脸demo中我使用的是调用本机摄像头完成人脸注册,本次demo根据业务需求的不同我采用文件上传的方式实现人脸注册。

效果演示

首页

注册

后端响应数据:

登录

后端响应数据:

项目结构

后端代码实现

1、BaiduAiUtils工具类封装

java 复制代码
package com.jzj.utils;

import com.baidu.aip.face.AipFace;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashMap;

/**
 * 百度AI工具类封装
 *
 * @author 黎明
 * @version 1.0
 * @date 2023/8/5 9:35
 */
@Component
@Slf4j
public class BaiduAiUtils {
    /*
    注入百度个人用户相关配置
     */
    @Value("${baidu.face.appId}")
    private String APP_ID;
    @Value("${baidu.face.apiKey}")
    private String API_KEY;
    @Value("${baidu.face.secretKey}")
    private String SECRET_KEY;
    @Value("${baidu.face.imageType}")
    private String IMAGE_TYPE;
    @Value("${baidu.face.groupId}")
    private String groupId;
    // 声明私有变量client,AipFace是百度人脸识别 API 的 Java 客户端类,用于与人脸识别服务进行通信。
    private AipFace client;
    // 用于存储一些参数配置(图片质量控制、活体检测控制)
    private HashMap<String, String> map = new HashMap<>();

    /*
    私有的构造函数,表明该类是一个单例类,只能通过静态方法获取实例
     */
    private BaiduAiUtils() {
        // 图片质量控制 NONE: 不进行控制 LOW:较低的质量要求 NORMAL: 一般的质量要求 HIGH: 较高的质量要求 默认 NONE
        map.put("quality_control", "NORMAL");
        // 活体检测控制 NONE: 不进行控制 LOW:较低的活体要求(高通过率 低拒绝率) NORMAL: 一般的活体要求(平衡的拒绝率, 通过率) HIGH: 较高的活体要求(高拒绝率 低通过率) 默认NONE
        map.put("liveness_control", "LOW");
    }

    /*
    用于在类初始化时执行client的初始化操作
     */
    @PostConstruct
    public void init() {
        client = new AipFace(APP_ID, API_KEY, SECRET_KEY);
    }

    /**
     * 人脸注册:用户照片存入人脸库中
     */
    public Boolean faceRegister(String userId, String image) {
        JSONObject res = client.addUser(image, IMAGE_TYPE, groupId, userId, map);
        log.info("人脸注册响应数据 :{}", res);
        Integer errorCode = res.getInt("error_code");
        return errorCode == 0 ? true : false;
    }

    /**
     * 人脸更新:更新人脸库中的用户照片
     */
    public Boolean faceUpdate(String userId, String image) {
        JSONObject res = client.updateUser(image, IMAGE_TYPE, groupId, userId, map);
        log.info("人脸更新响应数据 :{}", res);
        Integer errorCode = res.getInt("error_code");
        return errorCode == 0 ? true : false;
    }

    /**
     * 人脸检测:判断上传的图片中是否具有面部信息
     */
    public Boolean faceCheck(String image) {
        JSONObject res = client.detect(image, IMAGE_TYPE, map);
        log.info("人脸检测响应数据 :{}", res);
        if (res.has("error_code") && res.getInt("error_code") == 0) {
            JSONObject resultObject = res.getJSONObject("result");
            Integer faceNum = resultObject.getInt("face_num");
            return faceNum == 1 ? true : false;
        } else {
            return false;
        }
    }

    /**
     * 1.搜索人脸库中相似的人脸并返回数据
     * <p>
     * 2.判断人脸匹配得分(score)大于80分则认为是同一个人
     */
    public String faceSearch(String image) {
        JSONObject res = client.search(image, IMAGE_TYPE, groupId, map);
        log.info("人脸搜索响应数据 :{}", res);
        if (res.has("error_code") && res.getInt("error_code") == 0) {
            JSONObject result = res.getJSONObject("result");
            JSONArray userList = result.getJSONArray("user_list");
            if (userList.length() > 0) {
                JSONObject user = userList.getJSONObject(0);
                double score = user.getDouble("score");
                if (score > 80) {
                    return user.getString("user_id");
                }
            }
        }
        return null;
    }

}

2、FaceServiceImpl

java 复制代码
package com.jzj.service.impl;

import com.jzj.service.FaceService;
import com.jzj.utils.BaiduAiUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * FaceService实现类
 *
 * @author 黎明
 * @version 1.0
 * @date 2023/8/5 9:53
 */
@Service
@Slf4j
public class FaceServiceImpl implements FaceService {
    // 注入BaiduAiUtils
    @Autowired
    private BaiduAiUtils baiduAiUtils;

    /**
     * 人脸登录
     *
     * @param imagebast64 图片base64编码
     * @return userId
     */
    @Override
    public String loginByFace(StringBuffer imagebast64) {
        // 处理base64编码内容
        String image = imagebast64.substring(imagebast64.indexOf(",") + 1, imagebast64.length());
        return baiduAiUtils.faceSearch(image);
    }

    /**
     * 人脸注册
     *
     * @param userId      用户Id
     * @param imagebast64 图片base64编码
     * @return ""
     */
    @Override
    public Boolean registerFace(String userId, StringBuffer imagebast64) {
        // 处理base64编码内容
        String image = imagebast64.substring(imagebast64.indexOf(",") + 1, imagebast64.length());
        log.info("处理后的图片base64编码:{}",image);
        return baiduAiUtils.faceRegister(userId, image);
    }
}

3、FaceController

java 复制代码
package com.jzj.controller;

import com.alibaba.fastjson.JSON;
import com.jzj.common.Result;
import com.jzj.service.FaceService;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.UUID;

/**
 * controller控制层
 *
 * @author 黎明
 * @version 1.0
 * @date 2023/8/5 10:01
 */
@RestController
@RequestMapping("/face")
@Slf4j
public class FaceController {
    // 注入FaceService
    @Autowired
    private FaceService faceService;

    /**
     * 人脸登录
     * @param request 图片base64编码
     * @return userId
     */
    @RequestMapping("/login")
    public Result searchface(@RequestBody String request) {
        StringBuffer image = new StringBuffer(request);
        String userId = faceService.loginByFace(image);

        /*
        判断人脸库中是否有改用户
         */
        if (StringUtils.hasText(userId)){
            // !null且不为空,返回用户ID,和状态码:0
            return Result.ok(userId);
        }
        return Result.err(userId);
    }

    /**
     * 人脸注册
     * @param request 图片base64编码
     * @return res
     */
    @PostMapping("/register")
    public Result registerFace(@RequestBody String request) {
        StringBuffer image = new StringBuffer(request);
        String userId = UUID.randomUUID().toString().substring(0, 4);
        Boolean registerFace = faceService.registerFace(userId, image);

        /*
        判断是否注册成功
         */
        if (registerFace){
            // 注册成功,返回用户ID、状态码:0
            return Result.ok(userId);
        }
        // 注册失败,返回用户ID、状态码:1
        return Result.err(userId);
    }
}

前端代码实现

1、index

java 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录注册</title>
    <script type="application/javascript" src="js/axios_0.18.0_axios.min.js"></script>
    <link rel="stylesheet" href="css/login.css">
    <link rel="stylesheet" href="css/index.css">
</head>
<body>

<div class="container">
    <h1>欢迎来到网站</h1>
    <div class="button-container">
        <button class="login-button" onclick="showLoginForm()">登录</button>
        <button class="register-button" onclick="goToRegisterPage()">注册</button>
    </div>
</div>

<div id="loginForm" class="login-form">
    <div class="form-container">
        <h2>人脸识别登录</h2>
        <video id="video" width="320" height="240" autoplay></video>
        <button id="loginBtn">登录</button>
    </div>
</div>

<script>

    function showLoginForm() {
        var loginForm = document.getElementById("loginForm");
        loginForm.style.display = "block";

        // 获取视频流
        navigator.mediaDevices.getUserMedia({video: true, audio: false})
            .then(function (stream) {
                var video = document.getElementById("video");
                video.srcObject = stream;
            })
            .catch(function (error) {
                console.error("访问视频流出错: ", error);
            });
    }

    // 登录事件监听
    document.getElementById("loginBtn").addEventListener("click", function () {
        var video = document.getElementById("video");
        var canvas = document.createElement('canvas');
        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;
        var context = canvas.getContext('2d');
        context.drawImage(video, 0, 0, canvas.width, canvas.height);
        var imageBase64 = canvas.toDataURL("image/jpeg");

        axios.post("/face/login", {
            imagebast64: imageBase64
        }).then(function (response) {
            var res = response.data;
            if (res.code === 0) {
                alert("登录成功! UserId: " + res.userId);
                // 跳转到index页面
                window.location.href = "welcome.html";
            } else {
                alert("登录失败!");
            }
        }).catch(function (error) {
            console.error("登录错误: ", error);
        });
    });

    function goToRegisterPage() {
        window.location.href = "register.html";
    }
</script>
</body>
</html>

2、register

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户注册</title>
    <script type="application/javascript" src="js/axios_0.18.0_axios.min.js"></script>
</head>
<body>
<h1>Register</h1>
<input type="file" id="fileInput">
<button id="registerBtn">注册</button>

<script>
    // 获取注册按钮元素,并为其添加点击事件监听器
    document.getElementById("registerBtn").addEventListener("click", function () {
        // 获取文件选择框元素和选择的文件
        var fileInput = document.getElementById("fileInput");
        var file = fileInput.files[0];

        // 验证图片格式
        if (file) {
            var allowedFormats = ['image/png', 'image/jpeg', 'image/jpg', 'image/bmp'];
            if (allowedFormats.includes(file.type)) {
                // 创建一个 FileReader 对象,用于读取文件的内容
                var reader = new FileReader();

                // 文件读取完成后的处理逻辑
                reader.onloadend = function () {
                    // 从读取的结果中提取图像数据的 Base64 编码部分,使用正则表达式去除前缀部分
                    const imageBase64 = reader.result
                    // 发送POST请求
                    axios.post('/face/register', {
                        imagebast64: imageBase64
                    }).then(function (response) {
                        // 请求成功处理逻辑
                        console.log("响应数据:", response.data);
                        console.log("用户userId:", response.data.userId);
                        console.log("用户注册状态码:", response.data.code);
                        if (response.data.code === 0) {
                            alert("注册成功! UserId: " + response.data.userId);
                            // 跳转到index页面
                            window.location.href = "https://www.baidu.com";
                        } else {
                            alert("注册失败!");
                        }
                    }).catch(function (error) {
                        // 请求失败处理逻辑
                        console.error("错误注册信息: ", error);
                    });
                };
                // 读取文件内容,并将其保存在 reader.result 中
                reader.readAsDataURL(file);
            } else {
                // 文件格式不符合要求,显示错误提示
                alert("只能上传PNG、JPG、JPEG和BMP格式的图片!");
            }
        }
    });
</script>
</body>
</html>

详细代码已放到gitee仓库需要的源码请自取,链接https://gitee.com/bitliming/baidu_face.git

相关推荐
qq_124987075343 分钟前
基于SSM的动物保护系统的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·毕业设计·ssm·计算机毕业设计
Coder_Boy_1 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
2301_818732061 小时前
前端调用控制层接口,进不去,报错415,类型不匹配
java·spring boot·spring·tomcat·intellij-idea
汤姆yu5 小时前
基于springboot的尿毒症健康管理系统
java·spring boot·后端
暮色妖娆丶5 小时前
Spring 源码分析 单例 Bean 的创建过程
spring boot·后端·spring
biyezuopinvip6 小时前
基于Spring Boot的企业网盘的设计与实现(任务书)
java·spring boot·后端·vue·ssm·任务书·企业网盘的设计与实现
JavaGuide6 小时前
一款悄然崛起的国产规则引擎,让业务编排效率提升 10 倍!
java·spring boot
figo10tf7 小时前
Spring Boot项目集成Redisson 原始依赖与 Spring Boot Starter 的流程
java·spring boot·后端
zhangyi_viva7 小时前
Spring Boot(七):Swagger 接口文档
java·spring boot·后端
橙露7 小时前
Spring Boot 核心原理:自动配置机制与自定义 Starter 开发
java·数据库·spring boot