JAVA实现百度人脸检测截取人像

业务场景

最近有个需求,调用其他厂家的人脸分析,但是用户上传的图片千奇百怪,有相册截图、有远距离拍照,硬件厂家无法准确找到人脸,所以让我们处理下用户上传的人像图,将人像头部截取出来进行分析。

实现方法

共测试了两种方法,一种是基于OpenCV的JavaCV,还有一种是百度的人脸识别接口。大家可以根据下方的优缺点按需使用。
由于内容过多分成两篇,java代码是jdk1.8的,项目代码地址放在下方,对你有用的话别忘记点赞收藏

JavaCV所需的xml算法文件为网上查找的,缺点是使用效果不是特别精确,对于截图,小规格人脸识别不那么灵敏,可能需要算法调试。优点是对于比较明显的人像图扣取成功率还是比较高的。

百度人脸识别接口优点是精准,缺点是免费版有qps限制,每秒一次,不过后期处理的话问题不大。

项目demo码云地址

百度人脸识别截取方式

1 引入依赖

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.18</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>test01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>test01</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.12.0</version>
        </dependency>
        <!--hutool工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.4.4</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2 创建导入、导出文件夹

按需创建源文件、导出文件
按需放置

3 运行demo

import cn.hutool.core.img.ImgUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.*;

/**
 * @author cuixi
 * @description: 百度人脸识别demo
 * @date 2024/5/31
 */
@Slf4j
public class BaiduFaceDemo {
    // 百度申请的id和secret
    private static final String ID = "";
    private static final String SECRET = "";
    //原始图片地址
    private static final String ORIGINAL_IMG_PATH = "D:\\fac_test\\original_img\\";
    //转换后地址
    private static final String CONVERSION_IMG_PATH = "D:\\fac_test\\conversion_img\\";

    public static void main(String[] args) throws IOException {
        String token = getAuth();
        long count = 0;
        List<String> filePathList = getFiles(ORIGINAL_IMG_PATH);
        log.info("启动处理程序,文件" + filePathList.size() + "个");

        for (String filePath : filePathList) {
            log.info("开始处理图像:" + filePath);
            count++;
            try {
                exImg(token, filePath);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        log.info("结束处理程序:生成文件" + count + "个");
    }
    private static void exImg(String token, String path) throws IOException {
        System.out.println(token);
        HashMap<String, Object> map = new HashMap<>();
        String fileContentAsBase64 = getFileContentAsBase64(path, false);
        map.put("image", fileContentAsBase64);
        map.put("image_type", "BASE64");
        String post = HttpUtil.post("https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=" + token, map);
        JSONObject jsonObject = JSONObject.parseObject(post);
        System.out.println(post);
        JSONObject result = jsonObject.getJSONObject("result");
        JSONArray faceList = result.getJSONArray("face_list");
        List<JSONObject> list = faceList.toJavaList(JSONObject.class);
        for (JSONObject object : list) {
            JSONObject location = object.getJSONObject("location");
            File file = new File(path);
            BufferedImage image = ImageIO.read(file);
            imageCut(location, image, file);
        }
    }

    public static List<String> getFiles(String path) {
        List<String> filePathList = new ArrayList<>();
        File file = new File(path);
        // 如果这个路径是文件夹
        if (file.isDirectory()) {
            // 获取路径下的所有文件
            File[] files = file.listFiles();
            if (files != null) {
                for (File value : files) {
                    // 如果还是文件夹 递归获取里面的文件 文件夹
                    filePathList.add(value.getPath());
                }
            }
        }
        return filePathList;
    }
    public static String imageCut(JSONObject location, BufferedImage image, File file) throws IOException {
        Integer x = location.getInteger("left");
        Integer y = location.getInteger("top");
        Integer width = location.getInteger("width");
        Integer height = location.getInteger("height");
        FileOutputStream fileOutputStream = null;
        double base = 2;
        Rectangle rectangle = new Rectangle();
//        x,y其实就是坐标,能确定一个点位,指的是从那个点位开始截取,x0y0代表的是从左下角点开始裁剪
//        rectangle.x = x;
//        rectangle.y = y;
//        rectangle.width = width;
//        rectangle.height = height;
        int i1 = (int) (x - width / base);
        if (i1 < 0) {
            i1 = 0;
        }
        int i2 = (int) (y - height / base );
        if (i2 < 0) {
            i2 = 0;
        }
        rectangle.x = i1;
        rectangle.y = i2;
        rectangle.width = (int) (width * base);
        rectangle.height = (int) (height * base);
        System.out.println("x:" + x);
        System.out.println("width:" + width);
        System.out.println("y:" + y);
        System.out.println("height:" + height);
//        开始截取,返回一个image对象
        Image newImg = ImgUtil.cut(image, rectangle);
        String fileName = file.getName();
        String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
        String newFileName = fileName.substring(0, fileName.lastIndexOf(".")) + "_ex." + extension;
        try {
            byte[] bytes = ImgUtil.toBytes(newImg, "png");
            fileOutputStream = new FileOutputStream(CONVERSION_IMG_PATH + newFileName);
            fileOutputStream.write(bytes);
            log.info("输出图像到:" + CONVERSION_IMG_PATH + newFileName);
            return CONVERSION_IMG_PATH + newFileName;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            fileOutputStream.close();
        }
    }

    /**
     * 获取文件base64编码
     *
     * @param path      文件路径
     * @param urlEncode 如果Content-Type是application/x-www-form-urlencoded时,传true
     * @return base64编码信息,不带文件头
     * @throws IOException IO异常
     */
    static String getFileContentAsBase64(String path, boolean urlEncode) throws IOException {
        byte[] b = Files.readAllBytes(Paths.get(path));
        String base64 = Base64.getEncoder().encodeToString(b);
        if (urlEncode) {
            base64 = URLEncoder.encode(base64, "utf-8");
        }
        return base64;
    }

    /**
     * 获取权限token
     *
     * @return 返回示例:
     * {
     * "access_token": "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567",
     * "expires_in": 2592000
     * }
     */
    public static String getAuth() {
        return getAuth(ID, SECRET);
    }

    /**
     * 获取API访问token
     * 该token有一定的有效期,需要自行管理,当失效时需重新获取.
     *
     * @param ak - 百度云官网获取的 API Key
     * @param sk - 百度云官网获取的 Securet Key
     * @return assess_token 示例:
     * "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567"
     */
    public static String getAuth(String ak, String sk) {
        // 获取token地址
        String authHost = "https://aip.baidubce.com/oauth/2.0/token?";
        String getAccessTokenUrl = authHost
                // 1. grant_type为固定参数
                + "grant_type=client_credentials"
                // 2. 官网获取的 API Key
                + "&client_id=" + ak
                // 3. 官网获取的 Secret Key
                + "&client_secret=" + sk;
        try {
            URL realUrl = new URL(getAccessTokenUrl);
            // 打开和URL之间的连接
            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();
            // 获取所有响应头字段
            Map<String, List<String>> map = connection.getHeaderFields();
            // 遍历所有的响应头字段
//            for (String key : map.keySet()) {
//                System.err.println(key + "--->" + map.get(key));
//            }
            // 定义 BufferedReader输入流来读取URL的响应
            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String result = "";
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
            /**
             * 返回结果示例
             */
//            System.err.println("result:" + result);
            JSONObject jsonObject = JSONObject.parseObject(result);
            String access_token = jsonObject.getString("access_token");
            return access_token;
        } catch (Exception e) {
            System.err.printf("获取token失败!");
            e.printStackTrace(System.err);
        }
        return null;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值