基于百度Ai实现人脸登录
流程:
前端点击人脸登录获取二维码(里面是前端的人脸识别地址+唯一字符串),用户通过扫描二维码进入前端页面,前端不断请求登录状态,
前端登录页面中,前端调用手机或者电脑摄像头获取用户头像,首先是检测照片中是否有人头像,有 前端就调用登录页面进行登录,跳转信息页面,否则返回出错信息,当前端请求到的登录状态为1时表示登录成功,在手机端给用户提示登录成功。
package com.zhao.baiduai; import com.baidu.aip.util.Base64Util; import com.zhao.baiduai.domain.State; import com.zhao.baiduai.utils.BaiduAiUtil; import com.zhao.baiduai.utils.QRCodeUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; /** * 人脸登录模块 */ @RestController public class FaceController { @Autowired private QRCodeUtil qrCodeUtil; @Value("${qr.url}") private String content; @Autowired private BaiduAiUtil baiduAiUtil; @Resource private RedisTemplate<String,Object> redisTemplate; // @Autowired // private RedisTemplate redisTemplate; @GetMapping("redisTest") public String redisTest(){ ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue(); valueOperations.set("test","random1="+Math.random()); System.out.println(valueOperations.get("test")); return valueOperations.get("test").toString(); } /** * 生成用户登录的二维码 */ @GetMapping("getQRCode") public Map<String,Object> getQRCode() throws IOException { //创建标识 // Random random=new Random(); // content+="?code=QR"+ random.nextInt(1000); String uuid = UUID.randomUUID().toString().replace("-", ""); content+="?code="+ uuid; //存入当前二维码状态 String k="qrCode"+uuid; redisTemplate.boundValueOps(k).set(new State("-1"),10, TimeUnit.MINUTES); //TimeUnit.MINUTES 时间单位 10 失效时间 State队象 Map<String,Object> map=new HashMap<>(); map.put("code",uuid); map.put("qrCode",qrCodeUtil.crateQRCode(content)); return map; } /** * 检查二维码:登录页面轮询调用此方法,根据唯一标识code判断用户登录情况 * 查询二维码扫描状态 * state :-1, 0 登录失败 1 成功 */ @GetMapping("/qrcode/{code}") public String qrcodeCeck(@PathVariable(name = "code") String code) throws Exception { String key= "qrCode"+code; State state= (State)redisTemplate.opsForValue().get(key); if(state==null){ return "请求失败"; } String stateCode = state.getCode(); //等于-1 未登录 返回false if(stateCode.equals("-1")){ return "未授权"; }else if(stateCode.equals("0")){ return "登录失败"; } return "ok"; } /** * 人脸登录:根据落地页随机拍摄的面部头像进行登录 * 根据拍摄的图片调用百度云AI进行检索查找 */ @PostMapping("/{code}") public String loginByFace(@PathVariable(name = "code") String code, @RequestParam(name = "file") MultipartFile attachment) throws Exception { //人脸登录获取用户id(不为null登录成功)调用百度ai查询该图片的用户 String userId = baiduAiUtil.faceSearch(Base64Util.encode(attachment.getBytes())); State state = new State("0"); if(userId != null) { //登录 // 根据 userId 查询用户然后登录 返回 token给前端 这里测试就不返回了 //修改二维码状态 state.setCode("1"); redisTemplate.boundValueOps("qrCode"+code).set(state,10,TimeUnit.MINUTES); return "ok"+userId; }else{ redisTemplate.boundValueOps("qrCode"+code).set(state,10,TimeUnit.MINUTES); return "fail"; } } /** * 图像检测,判断图片中是否存在面部头像 */ @RequestMapping(value = "/checkFace", method = RequestMethod.POST) public String checkFace(@RequestParam(name = "file") MultipartFile attachment) throws Exception { String image = Base64Util.encode(attachment.getBytes()); Boolean aBoolean = baiduAiUtil.faceCheck(image); if (aBoolean) { return "ok"; }else{ return "fail"; } } }
百度人脸识别工具类
package com.zhao.baiduai.utils; import com.baidu.aip.face.AipFace; 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; @Component public class BaiduAiUtil { //AppID @Value("${ai.appId}") private String APP_ID; //API Key @Value("${ai.apiKey}") private String API_KEY; //Secret Key @Value("${ai.secretKey}") private String SECRET_KEY; //图片类型 @Value("${ai.imageType}") private String IMAGE_TYPE; //传入百度ai 创建的应用中的组名称 @Value("${ai.groupId}") private String groupId; private AipFace client; private HashMap<String, String> options = new HashMap<String, String>(); public BaiduAiUtil() { /** * 图片质量控制 NONE: 不进行控制 LOW:较低的质量要求 * NORMAL: 一般的质量要求 HIGH: 较高的质量要求 默认 * NONE */ options.put("quality_control", "NORMAL"); /** * 活体检测控制 NONE: 不进行控制 LOW:较低的活体要求 * (高通过率 低攻击拒绝率) NORMAL: 一般的活体要求(平衡 * 的攻击拒绝率, 通过率) HIGH: 较高的活体要求(高攻击拒绝 * 率 低通过率) 默认NONE */ options.put("liveness_control", "LOW"); } /** * @PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次 * 通常我们会是在Spring框架中使用到@PostConstruct注解 该注解的方法在整个Bean初始化中的执行顺序: * Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法) */ @PostConstruct public void init() { client = new AipFace(APP_ID, API_KEY, SECRET_KEY); } //判断用户是否已经注册了面部信息 public Boolean faceExist(String userId){ //error_code 0 存在 非0 不存在 JSONObject res=client.getUser(userId,groupId,null); Integer error_code = res.getInt("error_code"); return error_code==0; } /** * 人脸注册 :将用户照片存入人脸库中 */ public Boolean faceRegister(String userId, String image) { // 人脸注册 JSONObject res = client.addUser(image, IMAGE_TYPE, groupId, userId, options); Integer errorCode = res.getInt("error_code"); return errorCode == 0 ? true : false; //0表示成功 } /** * 人脸更新 :更新人脸库中的用户照片 */ public Boolean faceUpdate(String userId, String image) { // 人脸更新 JSONObject res = client.updateUser(image, IMAGE_TYPE, groupId, userId, options); Integer errorCode = res.getInt("error_code"); return errorCode == 0 ? true : false; } /** * 人脸检测:判断上传图片中是否具有面部头像 */ public Boolean faceCheck(String image) { JSONObject res = client.detect(image, IMAGE_TYPE, options); 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; } } /** * 人脸查找:查找人脸库中最相似的人脸并返回数据 * 处理:用户的匹配得分(score)大于80分,即可认为是同一个用户 */ public String faceSearch(String image) { JSONObject res = client.search(image, IMAGE_TYPE, groupId, options); 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; } }
二维码生成工具类
package com.zhao.baiduai.utils; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.client.j2se.MatrixToImageWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.QRCodeWriter; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import com.sun.org.apache.xml.internal.security.utils.Base64; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.imageio.ImageIO; import javax.servlet.ServletOutputStream; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.HashMap; /** * 生成二维码的工具类 * 因为这个工具类用的比较多 * 所以注入到spring中 */ @Component public class QRCodeUtil { /** * 生成Base64 二维码 */ public String crateQRCode(String content) throws IOException { System.out.println(content); ByteArrayOutputStream os = new ByteArrayOutputStream(); try { QRCodeWriter writer = new QRCodeWriter(); //content 扫描之后出来的信息 一般是网址 BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, 200, 200); BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix); ImageIO.write(bufferedImage, "png", os); //添加图片标识 return new String("data:image/png;base64," + Base64.encode(os.toByteArray())); } catch (Exception e) { e.printStackTrace(); } finally { os.close(); } return null; } }
依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zhao.face</groupId> <artifactId>loginFace</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.5.RELEASE</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <fastjson.version>1.2.47</fastjson.version> </properties> <dependencies> <!-- redis 依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!--spring2.0集成redis所需common-pool2--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.4.2</version> </dependency> <!-- 百度Ai依赖--> <dependency> <groupId>com.baidu.aip</groupId> <artifactId>java-sdk</artifactId> <version>4.8.0</version> </dependency> <!-- 二维码生成依赖--> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.16</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> </project>
项目地址:https://gitee.com/richOne/PeopleFaceLogin/tree/master

浙公网安备 33010602011771号