FaceServiceImpl.java 11.1 KB
package com.ruoyi.service.impl.dss;

import cn.hutool.core.convert.Convert;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.arcsoft.face.FaceEngine;
import com.arcsoft.face.FaceFeature;
import com.arcsoft.face.FaceInfo;
import com.arcsoft.face.FaceSimilar;
import com.arcsoft.face.enums.ErrorInfo;
import com.arcsoft.face.toolkit.ImageFactory;
import com.arcsoft.face.toolkit.ImageInfo;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.ResponseResult;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.sign.Base64;
import com.ruoyi.config.BsthSystemConfig;
import com.ruoyi.domain.driver.NewDriver;
import com.ruoyi.service.driver.NewDriverService;
import com.ruoyi.service.dss.FaceService;
import com.ruoyi.system.service.ISysDictDataService;
import com.ruoyi.utils.HttpClientUtil;
import com.ruoyi.utils.SpringApplicationUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

import static com.arcsoft.face.toolkit.ImageFactory.getRGBData;

/**
 * @author liujun
 * @date 2024年07月12日 10:51
 */
@Service
@Slf4j
public class FaceServiceImpl implements FaceService {
    @Autowired
    private NewDriverService newDriverService;
    @Autowired
    private BsthSystemConfig bsthSystemConfig;
    @Autowired
    private HttpClientUtil httpClientUtil;
    @Autowired
    private ISysDictDataService sysDictDataService;
    @Autowired
    private RuoYiConfig ruoYiConfig;


    @Override
    public NewDriver checkFace(NewDriver driver) {
        NewDriver driver1 = new NewDriver();
        driver1.setFaceSignIn(1);

        List<NewDriver> drivers = newDriverService.list(driver1);
        return checkFace(drivers, driver);
    }

    @Override
    public String getBase64ImagePath(String path) {
        String imageContent = convertFileToBase64(path);
        return StringUtils.isEmpty(imageContent) ? null : imageContent;
    }

    @Override
    public String getBase64ImageContent(String content) {
        return convertBase64(content.getBytes(StandardCharsets.UTF_8));
    }

    @Override
    public ResponseResult<String> getFaceFeatureImageContent(String content) {
        String json = null;
        Map<String, Object> parentMap = new HashMap<>();
        try {

            parentMap.put("method", "getfacelitefeature");
            parentMap.put("faceid", "1");
            String faceValue = FileUploadUtils.choosePrictureContent(content);
            parentMap.put("data", faceValue);

            json = httpClientUtil.doPost(bsthSystemConfig.getFaceFeatureURL(), parentMap, null);
            if (StringUtils.isEmpty(json)) {
                log.warn("获取面部特征失败,请检查数据:[{}],[{}],[{}]", json, bsthSystemConfig.getFaceFeatureURL(), JSON.toJSONString(parentMap));
                return ResponseResult.error("获取面部特征失败,请稍后再试");
            }
            json = StringUtils.substringAfter(json, "{");
            json = StringUtils.substringBeforeLast(json, "}");
            String[] results = StringUtils.split(json, ",");
            Map<String, String> resultMap = new HashMap<>();
            for (String result : results) {
                result = StringUtils.replace(result, "\\\"", "");
                String key = StringUtils.trim(StringUtils.substringBefore(result, ":"));
                String value = StringUtils.trim(StringUtils.substringAfter(result, ":"));
                resultMap.put(key, value);
            }


            if (!StringUtils.equalsIgnoreCase(resultMap.get("result"), "ok")) {
                log.warn("获取面部特征不成功,,请检查数据:[{}],[{}],[{}]", json, bsthSystemConfig.getFaceFeatureURL(), JSON.toJSONString(parentMap));
                return ResponseResult.error("获取面部特征失败,请稍后再试");
            }
            String faceFeature = Convert.toStr(resultMap.get("strlitefeature"));
            ResponseResult<String> responseResult = ResponseResult.success();
            responseResult.setData(faceFeature);
            return responseResult;
        } catch (Exception e) {
            log.error("获取面部特征异常,返回的结果是:[{}],[{}],[{}]", json, bsthSystemConfig.getFaceFeatureURL(), JSON.toJSONString(parentMap), e);
            return ResponseResult.error("获取面部特征异常,请稍后再试");
        }
    }

    @Override
    public ResponseResult<String> getFaceFeatureImagePath(String path) {
        String content = getBase64ImagePath(path);
        return getFaceFeatureImageContent(content);
    }

    @Override
    public ResponseResult<String> getFaceFeatureImageURL(String urlString) {
        String path = null;
        try {
//            String fileName = sysDictDataService.splitURL(urlString);
//             path = RuoYiConfig.getDownloadPath() + fileName+"/";
            byte[] bytes = HttpUtil.downloadBytes(urlString);
            String content = convertBase64(bytes);
            return getFaceFeatureImageContent(content);
        } finally {
//            if(StringUtils.isNotEmpty(path)) {
//                File file = new File()
//            }
        }
    }

    public static void main(String[] args) {
        FaceServiceImpl faceService = new FaceServiceImpl();
        faceService.getFaceFeatureImageURL("http://192.168.168.167:9000/alchohol/head/76408/driver.png");
    }

    private NewDriver checkFace(List<NewDriver> drivers, NewDriver sourceDriver) {
        if (CollectionUtils.isEmpty(drivers)) {
            return null;
        }
        if (StringUtils.isEmpty(sourceDriver.getImage())) {
            return null;
        }
        ByteArrayInputStream byteArrayInputStream = null;
        BufferedImage bufferedImage = null;
        try {
            String content = FileUploadUtils.choosePrictureContent(sourceDriver.getImage());
            byte[] sourceImageData = cn.hutool.core.codec.Base64.decode(content);
            byteArrayInputStream = new ByteArrayInputStream(sourceImageData);
            bufferedImage = ImageIO.read(byteArrayInputStream);
            ImageInfo sourceImage = ImageFactory.bufferedImage2ImageInfo(bufferedImage);


            FaceFeature sourceFaceFeature = generateFaceFeature(sourceDriver, sourceImage);
            if (Objects.isNull(sourceFaceFeature)) {
                return null;
            }


            Optional<NewDriver> optional = drivers.parallelStream().map(dr -> {
                float imageScore = checkFaceScore(dr, sourceFaceFeature);
                dr.setImageScore(imageScore);

                return dr;
            }).max(Comparator.comparing(NewDriver::getImageScore));

            if (Objects.nonNull(bufferedImage)) {
                bufferedImage.flush();
            }

            if (optional.isPresent() && Objects.nonNull(optional.get().getImageScore()) && optional.get().getImageScore() > 0.95) {
                return optional.get();
            }


            return null;
        } catch (IOException e) {
            sourceDriver.setImage(null);
            log.error("图片校验异常:[{}]", sourceDriver, e);
        } finally {

            IOUtils.closeQuietly(byteArrayInputStream);
        }
        return null;
    }

    private float checkFaceScore(NewDriver dr, FaceFeature sourceFaceFeature) {
        if (StringUtils.isEmpty(dr.getImage())) {
            log.error("头像路径为空;[{}]", dr);
            return -1;
        }
        StringBuilder builder = new StringBuilder();
        builder.append(RuoYiConfig.getDownloadPath1());
        if (!StringUtils.startsWith(dr.getImage(), "/")) {
            dr.setImage("/" + dr.getImage());
        }
        if (!StringUtils.startsWith(dr.getImage(), "/head")) {
            dr.setImage("/head" + dr.getImage());
        }
        builder.append(dr.getImage());

        File targetFile = new File(builder.toString());
        if (!targetFile.exists() || !targetFile.isFile()) {
            String url = sysDictDataService.combationValue(dr.getImage());
            try {
                FileUtils.forceMkdirParent(targetFile);
                HttpUtil.downloadFileFromUrl(url, targetFile);
            } catch (Exception e) {
                log.error("[{}] error", url, e);
            }

            if (!targetFile.isFile()) {
                return -1;
            }
        }

        ImageInfo target = getRGBData(targetFile);
        FaceFeature targetFaceFeature = generateFaceFeature(dr, target);
        if (Objects.isNull(targetFaceFeature)) {
            return -1;
        }

        //特征比对
        FaceSimilar faceSimilar = new FaceSimilar();
        int errorCode = SpringApplicationUtil.getBean(FaceEngine.class).compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);

        if (errorCode != ErrorInfo.MOK.getValue()) {
            log.error("人脸对比失败:[{}]", dr);
            return -1;
        }
        return faceSimilar.getScore();
    }

    private FaceFeature generateFaceFeature(NewDriver driver, ImageInfo image) {
        List<FaceInfo> faceInfoList = new ArrayList<>();
        int errorCode = SpringApplicationUtil.getBean(FaceEngine.class).detectFaces(image.getImageData(), image.getWidth(), image.getHeight(), image.getImageFormat(), faceInfoList);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            log.error("人脸对比失败,请检查数据:[{}];错误代码:[{}]", driver, errorCode);
            return null;
        }

        int size = CollectionUtils.size(faceInfoList);
        if (size == 0) {
            log.error("人脸对比失败,没有人脸特征数据:[{}];错误代码:[{}]", driver, errorCode);
            return null;
        }

        FaceFeature faceFeature = new FaceFeature();
        errorCode = SpringApplicationUtil.getBean(FaceEngine.class).extractFaceFeature(image.getImageData(), image.getWidth(), image.getHeight(), image.getImageFormat(), faceInfoList.get(0), faceFeature);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            log.error("提取对比特征失败,请检查数据:[{}];错误代码:[{}]", driver, errorCode);
            return null;
        }
        return faceFeature;
    }

    public String convertFileToBase64(String imgPath) {
        byte[] data = null;
        InputStream in = null;
        // 读取图片字节数组
        try {
            in = new FileInputStream(imgPath);
            System.out.println("文件大小(字节)=" + in.available());
            data = new byte[in.available()];
            in.read(data);
        } catch (IOException e) {
            log.error("转换图片异常:[{}]", imgPath, e);
            return null;
        } finally {
            IOUtils.closeQuietly(in);
        }
        return convertBase64(data);
    }

    private String convertBase64(byte[] data) {
        // 对字节数组进行Base64编码,得到Base64编码的字符串
        return Base64.encode(data);
    }

}