JAVA实现百度人脸检测截取人像
业务场景
最近有个需求,调用其他厂家的人脸分析,但是用户上传的图片千奇百怪,有相册截图、有远距离拍照,硬件厂家无法准确找到人脸,所以让我们处理下用户上传的人像图,将人像头部截取出来进行分析。
实现方法
共测试了两种方法,一种是基于OpenCV的JavaCV,还有一种是百度的人脸识别接口。大家可以根据下方的优缺点按需使用。
由于内容过多分成两篇,java代码是jdk1.8的,项目代码地址放在下方,对你有用的话别忘记点赞收藏。
JavaCV所需的xml算法文件为网上查找的,缺点是使用效果不是特别精确,对于截图,小规格人脸识别不那么灵敏,可能需要算法调试。优点是对于比较明显的人像图扣取成功率还是比较高的。
百度人脸识别接口优点是精准,缺点是免费版有qps限制,每秒一次,不过后期处理的话问题不大。
百度人脸识别截取方式
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;
}
}