SpringBoot实现人脸识别功能(阿里云人脸识别)并把人脸图片存入minio

要集成阿里云的人脸识别首先得开通人体人脸功能
视觉智能开放平台-控制台 (aliyun.com)
可以按需开通,首次开通有免费的5千次识别次数
开通好之后需要保存好AccessKey ID 和 AccessKey Secre代码中用的上

之后引入阿里云的人脸识别依赖

        <!--人脸识别(阿里云)-->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-facebody</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>viapi-utils</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-viapiutils</artifactId>
            <version>1.0.0</version>
        </dependency>

        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>facebody20191230</artifactId>
            <version>5.1.0</version>
        </dependency>

我们在数据库表设计中新建一张表,来存储图片路径和用户id(用来绑定人脸图片)

我们在比对之前得先录入人脸图片

/**
 * @Description:
 * @Author: XIAO_FEI
 * @CreateTime: 2024/01/09 15:25
 * @Version 1.0
 */
@RestController
@RequestMapping("/mta/v1/face")
public class ALiYunFaceController {

    @Autowired
    private ALiYunFaceService aLiYunFaceService;

    /**
     * 录入人脸识别
     *
     * @param multipartFile 图片文件
     * @return 录入结果
     */
    @PostMapping("/inputFace")
    public ResponseResult inputFace(@Param("file") MultipartFile multipartFile,
                                    @Param("id") Integer id) {

        return aLiYunFaceService.inputFace(multipartFile, id);
    }

 

/**
 * @Description:
 * @Author: XIAO_FEI
 * @CreateTime: 2024/01/09 15:26
 * @Version 1.0
 */

public interface ALiYunFaceService {

    ResponseResult inputFace(MultipartFile multipartFile, Integer id);


}

 

 实现类里面我们使用了人体活体检测和人脸属性检测,活体检测主要检测是不是卡通人物等等....

人脸属性检测主要是为了检测人脸数量是否满足一个

/**
 * @Description:
 * @Author: XIAO_FEI
 * @CreateTime: 2024/01/09 17:56
 * @Version 1.0
 */
@Service
@Slf4j
public class ALiYunFaceServiceImpl implements ALiYunFaceService {
    @Autowired
    private PersonnelFacesMapper personnelFacesMapper;
    @Autowired
    private PersonnelMapper personnelMapper;
    @Autowired
    private FileUploadServiceImpl fileUploadService;
    @Autowired
    private MinIOFileStorageServiceImpl minIOFileStorageService;
    
    // 这里就填写之前保存的 AccessKey ID 和 AccessKey Secret 

    private static final String ACCESS_KEY_ID = "****************";
    private static final String ACCESS_KEY_SECRET = "***************";
    private static final String ENDPOINT = "cn-shanghai"; // 访问的域名

    private static final DefaultProfile PROFILE = DefaultProfile.getProfile(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
    private static final IAcsClient CLIENT = new DefaultAcsClient(PROFILE);

    /**
     * 录入人脸照片
     *
     * @param multipartFile 图片文件
     * @param id            人员id
     * @return 录入结果
     */
    @Override
    public ResponseResult inputFace(MultipartFile multipartFile, Integer id) {

        // 1. 判断图片是否存在
        if (multipartFile.isEmpty()) {
            return ResponseResult.errorResult(5000, "图片文件不能为空");
        }


        FileUtils fileUtils = null;
        // 阿里云返回的图片路径
        String imageUrlTow = "";
        // minio 返回的路径
        String imageUpload = "";
        List<String> imagesPath = new ArrayList<>();
        try {
            fileUtils = FileUtils.getInstance(ACCESS_KEY_ID, ACCESS_KEY_SECRET);

            // 存入 minio
            // 文件路径  = 姓名+ 年月日
            Personnel personnel = personnelMapper.selectById(id);
            String prefix = personnel.getName();
            imageUpload = fileUploadService.imageUpload(multipartFile, prefix);
            imagesPath.add(imageUpload);
            imageUrlTow = fileUtils.upload(imageUpload);
            // 人脸活体检测
            if (!isLivingFace(imageUrlTow)) {
                // 删除 minio 图片
                minIOFileStorageService.delete(imagesPath);
                log.info("当前检测不是活物,删除图片成功");
                return ResponseResult.errorResult(5003, "当前检测不是活体");
            }

            // 人脸属性检测
            if (!RecognizeFace(imageUrlTow)) {
                // 删除 minio 图片
                minIOFileStorageService.delete(imagesPath);
                log.info("当前检测人数不止一个或者没有,删除图片成功");
                return ResponseResult.errorResult(5003, "当前检测人数不止一个或者没有");
            }

            // 把人脸的文件路径和人员 id 绑定在一起
            Warehousing(imageUpload, id);

        } catch (ClientException | IOException e) {
            log.info("人脸比对出现问题", e);
            // 删除 minio 图片
            minIOFileStorageService.delete(imagesPath);
            log.info("删除图片成功");
            return ResponseResult.errorResult(5003, "人脸录入出现故障请重试,或者联系管理员");
        }

        return ResponseResult.okResult("人脸录入成功");
    }

    /**
     * Warehousing      存入数据库
     *
     * @param imagePath 文件路径
     * @param id        人员 id
     */
    public void Warehousing(String imagePath, Integer id) {
        // 查询数据库中是否已存在该人员的人脸数据
        LambdaQueryWrapper<PersonnelFaces> lqw = new LambdaQueryWrapper<>();
        lqw.eq(PersonnelFaces::getPersonnelId, id);
        PersonnelFaces personnelFaces = personnelFacesMapper.selectOne(lqw);

        if (!ObjectUtils.isEmpty(personnelFaces)) {
            // 删除Minio中的文件
            List<String> pathUrls = Collections.singletonList(personnelFaces.getImagePath());
            minIOFileStorageService.delete(pathUrls);

            // 更新数据库中的人脸数据
            LambdaQueryWrapper<PersonnelFaces> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(PersonnelFaces::getPersonnelId, id);

            PersonnelFaces pf = new PersonnelFaces();
            pf.setImagePath(imagePath);
            pf.setUpdateTime(LocalDateTime.now());
            personnelFacesMapper.update(pf, wrapper);

        } else {
            // 插入新的人脸数据
            personnelFacesMapper.insert(
                    PersonnelFaces.builder()
                            .imagePath(imagePath)
                            .createTime(LocalDateTime.now())
                            .personnelId(id)
                            .build());
        }

    }

    /**
     * DetectLivingFace  人脸活体识别
     *
     * @param imageUrl 人脸活体识别
     * @return 是否为活体
     */
    public static boolean isLivingFace(String imageUrl) {
        DetectLivingFaceRequest request = new DetectLivingFaceRequest();
        request.setRegionId(ENDPOINT);

        List<DetectLivingFaceRequest.Tasks> tasksList = new ArrayList<>();
        DetectLivingFaceRequest.Tasks tasks1 = new DetectLivingFaceRequest.Tasks();
        tasks1.setImageURL(imageUrl);
        tasksList.add(tasks1);
        request.setTaskss(tasksList);

        try {
            DetectLivingFaceResponse response = CLIENT.getAcsResponse(request);
            log.info("人脸活体识别:{}", JSONObject.toJSONString(response));

            JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(response));
            jsonObject = JSONObject.parseObject(jsonObject.get("data").toString());

            int resultPass = jsonObject.toString().indexOf("pass");
            int resultBlock = jsonObject.toString().indexOf("block");

            return resultPass != -1 && resultBlock == -1;
        } catch (com.aliyuncs.exceptions.ClientException e) {
            log.error("阿里云客户端错误", e);
            return false;
        }
    }


  

    /**
     * RecognizeFace    人脸属性检测
     *
     * @param imageUrl 图片路径
     * @return 检测结果
     */
    public static boolean RecognizeFace(String imageUrl) {

        RecognizeFaceRequest request = new RecognizeFaceRequest();
        request.setRegionId("cn-shanghai");
        request.setImageURL(imageUrl);

        try {
            RecognizeFaceResponse response = CLIENT.getAcsResponse(request);
            System.out.println("人脸检测:" + new Gson().toJson(response));

            JSONObject jsonObject = JSONObject.parseObject(new Gson().toJson(response));
            jsonObject = JSONObject.parseObject((jsonObject.get("data").toString()));
            String faceCounts = jsonObject.get("faceCount").toString();
            if (Integer.parseInt(faceCounts) != 1) {
                return false;
            }
            String likeDoubles = jsonObject.get("faceProbabilityList").toString();
            likeDoubles = likeDoubles.substring(1, likeDoubles.length() - 1);
            if ("".equals(likeDoubles)) {
                return false;
            }
            String[] likeList = likeDoubles.split(",");
            if (likeList.length > 0) {
                String num_str = likeList[0].toString();
                double num_double = Double.parseDouble(num_str);
                // 满足条件返回 true
                return num_double > 0.7;
            }
            return false;
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            log.info("错误码: " + e.getErrCode());
            log.info("错误信息: " + e.getErrMsg());
            log.info("请求id" + e.getRequestId());
        }
        return false;
    }

 以上使用的是Mybatis-Plus插入的数据库,所以没有sql

当图片入库之后就得开始人脸比对了

再写一个接口来进行人脸比对,  实现思路就是,通过传入的图片对比保存在minio的图片
以上service实现类可以共用,我们在加一个人脸比对的方法就行

 /**
     * VerifyFace  人脸比对
     *
     * @param imageUrl_login    对比人脸图片1
     * @param imageUrl_register 对比人脸图片2
     */
    public static boolean VerifyFace(String imageUrl_login, String imageUrl_register) {

        CompareFaceRequest request = new CompareFaceRequest();
        request.setRegionId("cn-shanghai");
        request.setImageURLA(imageUrl_login);
        request.setImageURLB(imageUrl_register);

        try {
            CompareFaceResponse response = CLIENT.getAcsResponse(request);

            JSONObject jsonObject = JSONObject.parseObject(new Gson().toJson(response));
            jsonObject = JSONObject.parseObject((jsonObject.get("data").toString()));
            String confidence = jsonObject.get("confidence").toString();
            Float confidenceFloat = Float.parseFloat(confidence);

            if (confidenceFloat >= 0.71) {
                return true;
            } else {
                return false;
            }

        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            // 错误码
            log.info("人脸比对错误码" + e.getErrCode());
            // 错误信息
            log.info("人脸比对错误信息: " + e.getErrMsg());
            // 请求 id
            log.info("人脸比对请求id: " + e.getRequestId());
        }
        return true;
    }

所有图片均存入minio,如果需要存入minio代码可以评论在下方,当然有什么不对的地方欢迎指出,大家共同讨论,点个赞再走吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值