Springboot整合百度人脸识别功能实现注册和登录

您所在的位置:网站首页 百度人脸识别颜值92高吗 Springboot整合百度人脸识别功能实现注册和登录

Springboot整合百度人脸识别功能实现注册和登录

2024-07-14 02:08| 来源: 网络整理| 查看: 265

超详细多种人脸识别教程请参考CSDN中CodeDevMaster大佬的教程,链接如下:Java借助百度云人脸识别实现人脸注册、登录功能的完整示例_百度api 视频流人脸识别 java-CSDN博客

7f73f3fd9cf64ab3b76a2daccd82c6a3.png

本文档的百度AI人脸识别主要用于人脸登录等功能类似于手机上的面容解锁,需要上传到百度AI接口两张照片进行校验,如果需要类似腾讯的实名认证人脸识别真实姓名+身份证号+人脸的功能请参考上面的文档,且需要在百度AI进行企业认证调用V4接口。据百度AI工程师说之前的老用户可以使用V3接口的实名认证人脸识别,现在的新用户都需要进行企业认证调用V4接口。详细操作请参考百度AI人脸识别官方文档和错误码文档

官方API:人脸对比 - 人脸识别_人脸检测_人脸对比_人脸搜索_活体检测_百度智能云 (baidu.com)

官方错误码文档:人脸识别人脸检测人脸对比人脸搜索活体检测_百度智能云 (baidu.com)

项目压缩包链接:https://download.csdn.net/download/2301_79357346/89241774

如文档有错误请与我联系,谢谢

准备工作:

登录百度智能云控制台:https://console.bce.baidu.com/,开通人脸识别

81d6f6518d2a428bb3b5cc4d63c8739c.png

选择人脸识别项,创建人脸识别应用

26381562d7ba49f997bf4beccdb91f27.png

人脸识别接口默认全部选择,也可以选择添加其他接口。

a29db13675824a23a0b4c8abf0c7b119.png

得到应用ID、 API KEY、Secret Key

a43566ec25cf4c53bdac929007a78acd.png

添加依赖 org.springframework.boot spring-boot-starter-test org.springframework.boot spring-boot-starter-web com.alibaba druid-spring-boot-starter 1.1.10 org.springframework.boot spring-boot-starter-jdbc com.baomidou mybatis-plus-boot-starter 3.2.0 com.baomidou mybatis-plus-generator 3.2.0 mysql mysql-connector-java 8.0.16 org.springframework.boot spring-boot-starter-actuator org.apache.commons commons-lang3 com.aliyun.oss aliyun-sdk-oss 3.15.1 com.baidu.aip java-sdk 4.9.0 org.springframework.boot spring-boot-maven-plugin 项目结构参考如下

44afe35aae9e45818c79ba7232a63e3a.png

数据库参考如下

用户表要保证username用户名(账号)不能重复

63dbdd5182a14df6928057151c004993.png

创建BaiduAiConfig package com.baidu.config; import org.springframework.context.annotation.Configuration; @Configuration public class BaiduAiConfig {     public static final String AppId =你的APPID;     public static final String AK =你的API Key;     public static final String SK =你的Secret Key; }

我最初是在application.yml配置文件中写AppId、AK、SK但是类中获取不到所以才这么写的

创建OssUtil图片上传工具类

这里图片是保存到阿里云的OSS服务器中了,如果你没有阿里云的OSS服务器可以直接去阿里云官网免费注册

OSS文件上传详细教程请参考CSDN中liaozk_c大佬的教程:阿里云存储OSS文件上传详细教程_阿里oss文件上传-CSDN博客

02198358f1ae4aeb85c6e42d2df01d8a.png

package com.baidu.util; import com.aliyun.oss.ClientConfiguration; import com.aliyun.oss.OSSClient; import com.aliyun.oss.common.auth.DefaultCredentialProvider; import com.aliyun.oss.model.CannedAccessControlList; import com.aliyun.oss.model.PutObjectResult; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; @Component public class OssUtil {     private static String endPoint = "";                          // oss域名     private static String accessKeyId = "";                    // accessKeyId     private static String accessKeySecret = "";            // accessKeySecret     private static String bucketName = "";                      // 桶名称     private static String fileDir = "/img";                                // 当前文件所属文件夹(就是你想给文件传到那个文件夹下面)     //log日志对象     static Log log = LogFactory.getLog(OssUtil.class);     /**      * oss 工具客户端      */     private static OSSClient ossClient = null;     /**      * 上传文件至阿里云 OSS      * @param file 待上传文件      * 返回访问的全路径      */     public static String uploadFileToOss(MultipartFile file) {         // 初始化oss         initOSS(endPoint, accessKeyId, accessKeySecret);         String visitUrl = null;         try {             // 获取文件名             String orgName = file.getOriginalFilename();             if (StringUtils.isEmpty(orgName)) {                 orgName = file.getName();             }             orgName = getFileName(orgName);             //上传后的文件名 进行修饰             String fileRelName = fileDir + orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.indexOf("."));             // 上传至oss             PutObjectResult result = ossClient.putObject(bucketName, fileRelName, file.getInputStream());             if (result != null) {                 log.info("------OSS文件上传成功------");             }             // 拼接访问路径             visitUrl = "https://" + bucketName + "." + endPoint + "/" + fileRelName;             System.out.println("visit url : " + visitUrl);         } catch (IOException e) {             log.error(e.getMessage(), e);             return null;         }         return visitUrl;     }     /**      * 删除文件      * @param fileName      */     public static void deleteFileToOss(String fileName) { // 初始化oss initOSS(endPoint, accessKeyId, accessKeySecret);         ossClient.deleteObject(bucketName, fileName);     }     /**      * 初始化 oss 客户端      * @return      */     private static OSSClient initOSS(String endpoint, String accessKeyId, String accessKeySecret) {         if (ossClient == null) {             synchronized (OSSClient.class) {                 if (ossClient == null) {                     ossClient = new OSSClient(endpoint, new DefaultCredentialProvider(accessKeyId, accessKeySecret), new ClientConfiguration());                     // 设置权限(公开读)                     ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);                 }             }         }         return ossClient;     }     /**      * 判断文件名是否带盘符,重新处理      * @param fileName      * @return      */     public static String getFileName(String fileName){         //判断是否带有盘符信息         // Check for Unix-style path         int unixSep = fileName.lastIndexOf('/');         // Check for Windows-style path         int winSep = fileName.lastIndexOf('\\');         // Cut off at latest possible point         int pos = (winSep > unixSep ? winSep : unixSep);         if (pos != -1) {             // Any sort of path separator found...             fileName = fileName.substring(pos + 1);         }         //替换上传文件名字的特殊字符         fileName = fileName.replace("=", "").replace(",", "").replace("&", "").replace("#", "");         return fileName;     }     public static String getEndPoint() {         return endPoint;     }     public static void setEndPoint(String endPoint) {         OssUtil.endPoint = endPoint;     }     public static String getAccessKeyId() {         return accessKeyId;     }     public static void setAccessKeyId(String accessKeyId) {         OssUtil.accessKeyId = accessKeyId;     }     public static String getAccessKeySecret() {         return accessKeySecret;     }     public static void setAccessKeySecret(String accessKeySecret) {         OssUtil.accessKeySecret = accessKeySecret;     }     public static String getBucketName() {         return bucketName;     }     public static void setBucketName(String bucketName) {         OssUtil.bucketName = bucketName;     }     public static String getFileDir() {         return fileDir;     }     public static void setFileDir(String fileDir) {         OssUtil.fileDir = fileDir;     }     public static OSSClient getOssClient() {         return ossClient;     }     public static void setOssClient(OSSClient ossClient) {         OssUtil.ossClient = ossClient;     } } 创建Base64Util 该类主要是负责把前端传回来的MultipartFile类型的人脸识别图片文件转换为百度AI需要的base64格式 package com.baidu.util; import org.springframework.web.multipart.MultipartFile; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Base64; /** * Base64 工具类 */ public class Base64Util { private static final char last2byte = (char) Integer.parseInt("00000011", 2); private static final char last4byte = (char) Integer.parseInt("00001111", 2); private static final char last6byte = (char) Integer.parseInt("00111111", 2); private static final char lead6byte = (char) Integer.parseInt("11111100", 2); private static final char lead4byte = (char) Integer.parseInt("11110000", 2); private static final char lead2byte = (char) Integer.parseInt("11000000", 2); private static final char[] encodeTable = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; public Base64Util() { } public static String multipartFileToBase64(MultipartFile file) throws IOException { InputStream inputStream = file.getInputStream(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); int bytesRead; int bufferSize = 10 * 1024 * 1024; byte[] buffer = new byte[bufferSize]; // 可以根据需要调整缓冲区大小 while ((bytesRead = inputStream.read(buffer)) != -1) { byteArrayOutputStream.write(buffer, 0, bytesRead); } byte[] bytes = byteArrayOutputStream.toByteArray(); String base64String = Base64.getEncoder().encodeToString(bytes); // 不需要显式关闭 inputStream,因为 MultipartFile 的实现会负责关闭它 // byteArrayOutputStream.close(); // 如果需要,可以在这里关闭 ByteArrayOutputStream return base64String; } public static String encode(byte[] from) { StringBuilder to = new StringBuilder((int) ((double) from.length * 1.34D) + 3); int num = 0; char currentByte = 0; int i; for (i = 0; i < from.length; ++i) { for (num %= 8; num < 8; num += 6) { switch (num) { case 0: currentByte = (char) (from[i] & lead6byte); currentByte = (char) (currentByte >>> 2); case 1: case 3: case 5: default: break; case 2: currentByte = (char) (from[i] & last6byte); break; case 4: currentByte = (char) (from[i] & last4byte); currentByte = (char) (currentByte >> 6); } break; case 6: currentByte = (char) (from[i] & last2byte); currentByte = (char) (currentByte >> 4); } } to.append(encodeTable[currentByte]); } } if (to.length() % 4 != 0) { for (i = 4 - to.length() % 4; i > 0; --i) { to.append("="); } } return to.toString(); } } 创建CodeCompents package com.baidu.compents; public class CodeCompents { public final static String baidu_ai_imageType = "BASE64"; public final static String baidu_ai_groupId = "groupId"; } 创建UserBaiduAIController

登录接口需要传入用户名(账号)和登录时的图片然后获取数据库中注册的人脸识别照片的URL传到百度AI进行比对,如果数据库中没有该用户的人脸识别照片的URL则为该用户没有注册人脸识别,直接返回请先注册人脸识别

注册接口需要传入用户名(账号)和注册的人脸图片,然后将人脸识别的照片上传到阿里云的OSS服务器并获取保存的URL,然后将URL给到用户类里对应的属性中,再调用修改方法对数据库中的信息修改将注册的人脸识别图片URL保存到数据库中

package com.baidu.controller; import com.baidu.aip.face.AipFace; import com.baidu.aip.face.MatchRequest; import com.baidu.compents.CodeCompents; import com.baidu.config.BaiduAiConfig; import com.baidu.pojo.UserBaiduai; import com.baidu.service.UserBaiduAIService; import com.baidu.util.Base64Util; import com.baidu.util.OssUtil; import org.apache.commons.lang3.ObjectUtils; import org.json.JSONException; import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @RestController @RequestMapping("/baiduAI") public class UserBaiduAIController { @Autowired private UserBaiduAIService userBaiduAIService; /** * 账号+人脸校验 * @param userName * @param file * @throws Exception */ @PostMapping("/loginBaiduAi") public void loginBaiduAi(String userName, MultipartFile file) throws Exception { // 传入appId、apiKey、secretkey。创建Java代码和百度云交互的Client对象 AipFace client = new AipFace(BaiduAiConfig.AppId, BaiduAiConfig.AK, BaiduAiConfig.SK); // 登录图片 // MultipartFile类型转换Base64字符串格式 String loginImageBase64 = Base64Util.multipartFileToBase64(file); // 根据用户名获取用户信息 UserBaiduai one = userBaiduAIService.findByName(userName); /* 判断该用户是否注册了人脸 如果没有注册则不进行校验 如果注册了则进行校验 */ if (!ObjectUtils.isEmpty(one.getPhoto())){ // 用户注册的人脸的照片存储路径 String comparedImageUrl = one.getPhoto(); /* 传入参数进行校验 返回值为两张照片的相似度 */ Double faceComparison = faceComparison(client, loginImageBase64, comparedImageUrl); if (faceComparison > 85) { System.out.println(one.getUsername()); System.out.println("人脸识别登录成功"); } else { System.out.println("人脸识别登录失败"); } }else { System.out.println("请先录入人脸信息"); } } @PostMapping("registerBaiduAi") public void registerBaiduAi(String userName,MultipartFile file) throws IOException, JSONException { // 传入appId、apiKey、secretkey。创建Java代码和百度云交互的Client对象 AipFace client = new AipFace(BaiduAiConfig.AppId, BaiduAiConfig.AK, BaiduAiConfig.SK); // 根据用户名获取用户信息 UserBaiduai one = userBaiduAIService.findByName(userName); // 判断用户是否注册过人脸识别 if(!ObjectUtils.isEmpty(one.getPhoto())){ // 如果有则先删除原来注册的人脸照片 // 假设图片URL是https://canghai0190.oss-cn-beijing.aliyuncs.com/img/1714270552688.png // 那么我们要截取com/后面的文件路径名称传入方法进行删除 int index = one.getPhoto().indexOf("com/"); String fileName = null; if (index != -1) { fileName = one.getPhoto().substring(index + 4); // 截取 "com/" 后面的内容 } else { fileName = ""; } System.out.println(fileName); OssUtil.deleteFileToOss(fileName); } // MultipartFile类型转换Base64字符串格式 String registerImageBase64 = Base64Util.multipartFileToBase64(file); // 传入可选参数调用接口 HashMap options = new HashMap(); options.put("user_info", "user's info"); options.put("quality_control", "NORMAL"); options.put("liveness_control", "LOW"); options.put("action_type", "REPLACE"); /* 调用api方法完成人脸注册 image 图片的url或者base64字符串 imageType 图片形式(URL,BASE64) groupId 组Id(固定一个字符串) userId 用户Id options hashMap基本参数配置 */ JSONObject res = client.addUser(registerImageBase64, CodeCompents.baidu_ai_imageType, CodeCompents.baidu_ai_groupId, String.valueOf(userName), options); if (res.getInt("error_code")==0){ //上传人脸识别图片到oss String url = OssUtil.uploadFileToOss(file); //将人脸识别信息和用户信息绑定存入数据库 UserBaiduai userBaiduai = userBaiduAIService.findByName(userName); userBaiduai.setPhoto(url); userBaiduAIService.update(userBaiduai); //更新redis中的用户信息 // updateUser(hmsUser); System.out.println("人脸注册成功"); }else { System.out.println("人脸注册失败"); } System.out.println(res.toString(2)); } static Double faceComparison(AipFace client, String loginImageBase64, String comparedImageUrl) throws Exception { // 将图片的URL传递给百度API MatchRequest req2 = new MatchRequest(comparedImageUrl, "URL"); // 将前端传过来的图片传递给百度API MatchRequest req1 = new MatchRequest(loginImageBase64, CodeCompents.baidu_ai_imageType); // 讲MatchRequest信息存入list集合中 ArrayList requests = new ArrayList(); requests.add(req1); requests.add(req2); // 进行人脸比对 返回值是json串 JSONObject match = client.match(requests); System.out.println(match.toString(2)); // 返回两张照片的相似度 return match.getJSONObject("result").getDouble("score"); } } 测试

由于本人vue会的是在不多所以前端没有写出来,想要页面的请参考我最上面放的CodeDevMaster大佬的链接,教程最后面有vue前端的教程

为了测试我这边就使用Postman进行测试

需要的参数有

params中userName参数

fa7778e4032747be968c99618c9ac989.png

body中名为file的file类型的一个照片文件

1164709118074bbf84222044337e0f35.png

注册接口的测试结果 52466d0948754e7ab91c5e7fb23ff523.png登录接口的测试结果

登录接口人脸正确的结果

96be24f728e344f19a5367f5b46e7f5e.png

登录接口人脸识别的接口

6b8c22ac32d14e3583479f20b861c8dc.png

怎么判断两张照片是否为同一个人?

大家应该可以看到我上面两次测试都用红框框起来的score这个值,这个值的意思是传入百度AI的登录的人脸照片和数据库中注册的人脸照片的匹配值,匹配值越高则大概率是同一个人,匹配值越低则说明越不可能是同一个人,然后我们只需要根据这个值进行判断即可,一半是相似度大于等于85即可判断为同一个人,小于85则判断为不是同一个人

返回的JSON中各个属性是什么意思?

score 人脸相似度得分 face_list 人脸信息列表 face_token 人脸的唯一标志 log_id 是请求标识码,随机数,唯一 location 是人脸在图片中的位置 error_code 错误码 error_msg 误描述信息,帮助理解和解决发生的错误



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3