基于百度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";
        }
    }

}
View Code

百度人脸识别工具类

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;
    }
}
View Code

二维码生成工具类

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;
    }

}
View Code

依赖

<?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>
View Code

 

项目地址:https://gitee.com/richOne/PeopleFaceLogin/tree/master

posted @ 2020-02-03 23:01  Angry-rookie  阅读(706)  评论(0)    收藏  举报