mirror of
https://github.com/geekwenjie/SmartJavaAI.git
synced 2026-09-09 19:18:52 +00:00
修复人脸识别算法facenet-pytorch实现方式
This commit is contained in:
48
README.md
48
README.md
@@ -61,14 +61,16 @@
|
||||
- **RetinaFace 模型**[[GitHub]](https://github.com/deepinsight/insightface/tree/master/detection/retinaface):一个高效的深度学习人脸检测模型,支持高精度的人脸检测,但目前不支持人脸比对
|
||||
- **Ultra-Light-Fast-Generic-Face-Detector-1MB** [[GitHub\]](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB):一个轻量级的人脸检测模型,适用于需要较低延迟和较小模型尺寸的应用场景。
|
||||
- **Seetaface6** [[GitHub\]](https://github.com/seetafaceengine/SeetaFace6):是中科视拓最新开放的商业正式级版本,支持人脸检测、关键点定位、人脸识别。同时增加了活体检测、质量评估、年龄性别估计。并且响应时事,开放了口罩检测以及戴口罩的人脸识别模型
|
||||
- **[facenet-pytorch](https://github.com/timesler/facenet-pytorch)** [[GitHub\]](https://github.com/seetafaceengine/SeetaFace6):这是 pytorch 中 Inception Resnet (V1) 模型的存储库,在 VGGFace2 和 CASIA-Webface 上进行了预训练。Pytorch 模型权重使用从 David Sandberg 的 [tensorflow Facenet repo](https://github.com/davidsandberg/facenet) 移植的参数进行初始化。该存储库中还包含 MTCNN 的高效 pytorch 实现,用于推理之前的人脸检测。这些模型也是经过预训练的。据我们所知,这是最快的 MTCNN 实现。
|
||||
|
||||
### 模型对比及下载地址
|
||||
### 人脸模型对比及下载地址
|
||||
|
||||
| 模型名称 | 下载地址 | 文件大小 | 适用场景 | 兼容系统 |
|
||||
| :-----------------------: | :----------------------------------------------------------: | :------: | :---------------: | ------------------- |
|
||||
| retinaface | [下载](https://resources.djl.ai/test-models/pytorch/retinaface.zip) | 110MB | 高精度人脸检测 | Windows/Linux/MacOS |
|
||||
| ultralightfastgenericface | [下载](https://resources.djl.ai/test-models/pytorch/ultranet.zip) | 1.7MB | 高速人脸检测 | Windows/Linux |
|
||||
| seetaface6 | [下载](https://pan.baidu.com/s/1hfNacA8ISV2qHrycjOkgqA?pwd=1234) | 288MB | 人脸检测/人脸识别 | Windows/Linux |
|
||||
| ultralightfastgenericface | [下载](https://resources.djl.ai/test-models/pytorch/ultranet.zip) | 1.7MB | 高速人脸检测 | Windows/Linux/MacOS |
|
||||
| seetaface6 | [下载](https://pan.baidu.com/s/1hfNacA8ISV2qHrycjOkgqA?pwd=1234) | 288MB | 人脸检测/人脸识别 | Windows |
|
||||
| facenet-pytorch | [下载](https://resources.djl.ai/test-models/pytorch/face_feature.zip) | 104MB | 人脸识别 | Windows/Linux/MacOS |
|
||||
|
||||
## 环境要求
|
||||
|
||||
@@ -82,7 +84,7 @@
|
||||
>
|
||||
> (1)默认算法(RetinaFace)或轻量算法(Ultra-Light-Fast-Generic-Face-Detector )都为python算法,兼容 Windows、Linux、MacOS,Android 等系统,SmartJavaAI首次启动将自动下载模型到及依赖库到本地(.djl.ai隐藏文件夹),建议保持网络畅通。初始化完成后,后续启动可实现毫秒级响应。在无网络环境下,可指定本地模型路径(需提前下载模型包)。目前,这两种算法不支持人脸识别或人脸比对功能。
|
||||
>
|
||||
> (2)Seetaface6 采用 C++ 编写,兼容 Windows、CentOS、Ubuntu 等系统。创建算法时,将自动加载对应系统的依赖库。Seetaface6 支持全功能人脸处理(人脸检测、人脸比对 1:1 或 1:N)。SmartJavaAI 通过 JNI 调用 C++ 接口,不支持在线下载模型,需手动下载并存储至本地。使用人脸比对等功能时,需要将项目中db/faces-data.db存放到您本地路径下并在config中指定人脸库路径。
|
||||
> (2)Seetaface6 采用 C++ 编写,兼容 Windows、CentOS、Ubuntu 等系统,虽然Seetaface6 支持linux,但是我们目前仅实现了windows,如果后续对linux需求多,我们将兼容linux。Seetaface6 支持全功能人脸处理(人脸检测、人脸比对 1:1 或 1:N)。SmartJavaAI 通过 JNI 调用 C++ 接口,不支持在线下载模型,需手动下载并存储至本地。使用人脸比对等功能时,需要将项目中db/faces-data.db存放到您本地路径下并在config中指定人脸库路径。
|
||||
|
||||
### 1. 安装人脸算法依赖
|
||||
|
||||
@@ -93,7 +95,7 @@
|
||||
<dependency>
|
||||
<groupId>ink.numberone</groupId>
|
||||
<artifactId>smartjavaai-face</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>1.0.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
@@ -150,7 +152,7 @@ log.info("相似度:{}", similar);
|
||||
|
||||
|
||||
|
||||
### 6. 人脸特征提取及比对
|
||||
### 6. 人脸特征提取及比对(seetaface6)
|
||||
|
||||
```java
|
||||
// 初始化配置
|
||||
@@ -169,7 +171,24 @@ float similar = currentAlgorithm.calculSimilar(feature1, feature2);
|
||||
log.info("相似度:{}", similar);
|
||||
```
|
||||
|
||||
### 7. 注册及搜索人脸(1:N)
|
||||
### 7. 人脸特征提取及比对(facenet-pytorch)
|
||||
|
||||
```java
|
||||
//创建脸算法
|
||||
FaceAlgorithm featureAlgorithm = FaceAlgorithmFactory.createFaceFeatureAlgorithm();
|
||||
//提取身份证人脸特征
|
||||
float[] feature1 = featureAlgorithm.featureExtraction("src/main/resources/kana1.jpg");
|
||||
float[] feature2 = featureAlgorithm.featureExtraction("src/main/resources/kana2.jpg");
|
||||
if (feature1 != null && feature2 != null) {
|
||||
//相似度在0.8至0.85及以上时,可判定为同一人,但具体阈值可能因图片而异,存在一定误差。
|
||||
float similar = featureAlgorithm.calculSimilar(feature1, feature2);
|
||||
log.info("相似度:{}", similar);
|
||||
} else {
|
||||
log.warn("人脸特征提取失败");
|
||||
}
|
||||
```
|
||||
|
||||
### 8. 注册及搜索人脸(1:N)
|
||||
|
||||
```java
|
||||
// 初始化配置
|
||||
@@ -195,7 +214,7 @@ if(faceResult != null){
|
||||
}
|
||||
```
|
||||
|
||||
### 8. 人脸检测(离线下载模型)
|
||||
### 9. 人脸检测(离线下载模型)
|
||||
|
||||
```java
|
||||
// 初始化配置
|
||||
@@ -250,7 +269,16 @@ ImageUtils.drawBoundingBoxes(image, result, imagePath.toAbsolutePath().toString(
|
||||
- **微信**: deng775747758 (请备注:SmartJavaAI)
|
||||
- **Email**: 775747758@qq.com
|
||||
|
||||
|
||||
|
||||
🚀 **如果这个项目对你有帮助,别忘了点个 Star ⭐!你的支持是我持续优化升级的动力!** ❤️
|
||||
|
||||
|
||||
|
||||
|
||||
## 更新日志
|
||||
|
||||
## [v1.0.6] - 2025-04-01
|
||||
- 修复人脸识别算法facenet-pytorch实现方式
|
||||
- 优化Seetaface6算法,兼容jdk高版本
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<dependency>
|
||||
<groupId>ink.numberone</groupId>
|
||||
<artifactId>smartjavaai-face</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>1.0.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -13,8 +13,10 @@ import smartai.examples.utils.ImageUtils;
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RasterFormatException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.LinkOption;
|
||||
@@ -30,7 +32,7 @@ public class FaceDemo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
featureComparison();
|
||||
featureExtractionAndCompare2();
|
||||
//detectFace2();
|
||||
//verifyIDCard();
|
||||
} catch (Exception e) {
|
||||
@@ -44,29 +46,26 @@ public class FaceDemo {
|
||||
* 特点:识别精度高,高速
|
||||
* 应用场景:如监控摄像头、智能安防系统等需要高精度检测的场合
|
||||
*/
|
||||
public static void detectFace() throws Exception {
|
||||
// 创建并启动计时器
|
||||
StopWatch sw = StopWatch.createStarted();
|
||||
//创建人脸算法
|
||||
FaceAlgorithm currentAlgorithm = FaceAlgorithmFactory.createFaceAlgorithm();
|
||||
sw.stop();
|
||||
log.info("创建人脸算法耗时:" + sw.getTime() + "ms");
|
||||
sw.reset();
|
||||
sw.start();
|
||||
//使用图片路径检测
|
||||
FaceDetectedResult result = currentAlgorithm.detect("src/main/resources/largest_selfie.jpg");
|
||||
sw.stop();
|
||||
log.info("人脸检测耗时:" + sw.getTime() + "ms");
|
||||
log.info("人脸检测结果:{}", JSONObject.toJSONString(result));
|
||||
//使用图片流检测
|
||||
File input = new File("src/main/resources/largest_selfie.jpg");
|
||||
//FaceDetectedResult result = currentAlgorithm.detect(new FileInputStream(input));
|
||||
//log.info("人脸检测结果:{}", JSONObject.toJSONString(result));
|
||||
BufferedImage image = ImageIO.read(input);
|
||||
//创建保存路径
|
||||
Path imagePath = Paths.get("output").resolve("retinaface_detected.jpg");
|
||||
//绘制人脸框
|
||||
ImageUtils.drawBoundingBoxes(image, result, imagePath.toAbsolutePath().toString());
|
||||
public static void detectFace(){
|
||||
try {
|
||||
//创建人脸算法
|
||||
FaceAlgorithm currentAlgorithm = FaceAlgorithmFactory.createFaceAlgorithm();
|
||||
//使用图片路径检测
|
||||
FaceDetectedResult result = currentAlgorithm.detect("src/main/resources/largest_selfie.jpg");
|
||||
log.info("人脸检测结果:{}", JSONObject.toJSONString(result));
|
||||
//使用图片流检测
|
||||
File input = new File("src/main/resources/largest_selfie.jpg");
|
||||
//FaceDetectedResult result = currentAlgorithm.detect(new FileInputStream(input));
|
||||
//log.info("人脸检测结果:{}", JSONObject.toJSONString(result));
|
||||
BufferedImage image = ImageIO.read(input);
|
||||
//创建保存路径
|
||||
Path imagePath = Paths.get("output").resolve("retinaface_detected.jpg");
|
||||
//绘制人脸框
|
||||
ImageUtils.drawBoundingBoxes(image, result, imagePath.toAbsolutePath().toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -76,29 +75,25 @@ public class FaceDemo {
|
||||
* 特点:高速,准确率略低
|
||||
* 应用场景:如监控摄像头、智能安防系统等需要高精度检测的场合
|
||||
*/
|
||||
public static void detectFace2() throws Exception {
|
||||
// 创建并启动计时器
|
||||
StopWatch sw = StopWatch.createStarted();
|
||||
//创建轻量人脸算法
|
||||
FaceAlgorithm currentAlgorithm = FaceAlgorithmFactory.createLightFaceAlgorithm();
|
||||
sw.stop();
|
||||
log.info("创建人脸算法耗时:" + sw.getTime() + "ms");
|
||||
sw.reset();
|
||||
sw.start();
|
||||
//使用图片路径检测
|
||||
FaceDetectedResult result = currentAlgorithm.detect("src/main/resources/largest_selfie.jpg");
|
||||
sw.stop();
|
||||
log.info("人脸检测耗时:" + sw.getTime() + "ms");
|
||||
log.info("轻量人脸检测结果:{}", JSONObject.toJSONString(result));
|
||||
//使用图片流检测
|
||||
//File imageFile = new File("/Users/wenjie/Downloads/djl-master/examples/src/test/resources/largest_selfie.jpg");
|
||||
//FaceDetectedResult result = currentAlgorithm.detect(new FileInputStream(imageFile));
|
||||
File input = new File("src/main/resources/largest_selfie.jpg");
|
||||
BufferedImage image = ImageIO.read(input);
|
||||
//创建保存路径
|
||||
Path imagePath = Paths.get("output").resolve("retinaface_detected.jpg");
|
||||
//绘制人脸框
|
||||
ImageUtils.drawBoundingBoxes(image, result, imagePath.toAbsolutePath().toString());
|
||||
public static void detectFace2(){
|
||||
try {
|
||||
//创建轻量人脸算法
|
||||
FaceAlgorithm currentAlgorithm = FaceAlgorithmFactory.createLightFaceAlgorithm();
|
||||
//使用图片路径检测
|
||||
FaceDetectedResult result = currentAlgorithm.detect("src/main/resources/largest_selfie.jpg");
|
||||
log.info("轻量人脸检测结果:{}", JSONObject.toJSONString(result));
|
||||
//使用图片流检测
|
||||
//File imageFile = new File("/Users/wenjie/Downloads/djl-master/examples/src/test/resources/largest_selfie.jpg");
|
||||
//FaceDetectedResult result = currentAlgorithm.detect(new FileInputStream(imageFile));
|
||||
File input = new File("src/main/resources/largest_selfie.jpg");
|
||||
BufferedImage image = ImageIO.read(input);
|
||||
//创建保存路径
|
||||
Path imagePath = Paths.get("output").resolve("retinaface_detected.jpg");
|
||||
//绘制人脸框
|
||||
ImageUtils.drawBoundingBoxes(image, result, imagePath.toAbsolutePath().toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -109,34 +104,38 @@ public class FaceDemo {
|
||||
* 特点:识别精度高,高速
|
||||
* 应用场景:如监控摄像头、智能安防系统等需要高精度检测的场合
|
||||
*/
|
||||
public static void detectFaceOffine() throws Exception {
|
||||
// 初始化配置
|
||||
ModelConfig config = new ModelConfig();
|
||||
config.setAlgorithmName("retinaface");//人脸算法模型,目前支持:retinaface/ultralightfastgenericface/seetaface6
|
||||
//config.setAlgorithmName("ultralightfastgenericface");//轻量模型
|
||||
config.setConfidenceThreshold(FaceConfig.DEFAULT_CONFIDENCE_THRESHOLD);//置信度阈值
|
||||
config.setMaxFaceCount(FaceConfig.MAX_FACE_LIMIT);//每张特征图保留的最大候选框数量
|
||||
//nms阈值:控制重叠框的合并程度,取值越低,合并越多重叠框(减少误检但可能漏检);取值越高,保留更多框(增加检出但可能引入冗余)
|
||||
config.setNmsThresh(FaceConfig.NMS_THRESHOLD);
|
||||
//模型下载地址:
|
||||
//retinaface: https://resources.djl.ai/test-models/pytorch/retinaface.zip
|
||||
//ultralightfastgenericface: https://resources.djl.ai/test-models/pytorch/ultranet.zip
|
||||
//改为模型存放路径
|
||||
config.setModelPath("/Users/wenjie/Documents/develop/face_model/retinaface.pt");
|
||||
//创建人脸算法
|
||||
FaceAlgorithm currentAlgorithm = FaceAlgorithmFactory.createFaceAlgorithm(config);
|
||||
//使用图片路径检测
|
||||
FaceDetectedResult result = currentAlgorithm.detect("src/main/resources/largest_selfie.jpg");
|
||||
log.info("人脸检测结果:{}", JSONObject.toJSONString(result));
|
||||
//使用图片流检测
|
||||
File input = new File("src/main/resources/largest_selfie.jpg");
|
||||
//FaceDetectedResult result = currentAlgorithm.detect(new FileInputStream(input));
|
||||
//logger.info("人脸检测结果:{}", JSONObject.toJSONString(result));
|
||||
BufferedImage image = ImageIO.read(input);
|
||||
//创建保存路径
|
||||
Path imagePath = Paths.get("output").resolve("retinaface_detected.jpg");
|
||||
//绘制人脸框
|
||||
ImageUtils.drawBoundingBoxes(image, result, imagePath.toAbsolutePath().toString());
|
||||
public static void detectFaceOffine(){
|
||||
try {
|
||||
// 初始化配置
|
||||
ModelConfig config = new ModelConfig();
|
||||
config.setAlgorithmName("retinaface");//人脸算法模型,目前支持:retinaface/ultralightfastgenericface/seetaface6
|
||||
//config.setAlgorithmName("ultralightfastgenericface");//轻量模型
|
||||
config.setConfidenceThreshold(FaceConfig.DEFAULT_CONFIDENCE_THRESHOLD);//置信度阈值
|
||||
config.setMaxFaceCount(FaceConfig.MAX_FACE_LIMIT);//每张特征图保留的最大候选框数量
|
||||
//nms阈值:控制重叠框的合并程度,取值越低,合并越多重叠框(减少误检但可能漏检);取值越高,保留更多框(增加检出但可能引入冗余)
|
||||
config.setNmsThresh(FaceConfig.NMS_THRESHOLD);
|
||||
//模型下载地址:
|
||||
//retinaface: https://resources.djl.ai/test-models/pytorch/retinaface.zip
|
||||
//ultralightfastgenericface: https://resources.djl.ai/test-models/pytorch/ultranet.zip
|
||||
//改为模型存放路径
|
||||
config.setModelPath("/Users/wenjie/Documents/develop/face_model/retinaface.pt");
|
||||
//创建人脸算法
|
||||
FaceAlgorithm currentAlgorithm = FaceAlgorithmFactory.createFaceAlgorithm(config);
|
||||
//使用图片路径检测
|
||||
FaceDetectedResult result = currentAlgorithm.detect("src/main/resources/largest_selfie.jpg");
|
||||
log.info("人脸检测结果:{}", JSONObject.toJSONString(result));
|
||||
//使用图片流检测
|
||||
File input = new File("src/main/resources/largest_selfie.jpg");
|
||||
//FaceDetectedResult result = currentAlgorithm.detect(new FileInputStream(input));
|
||||
//logger.info("人脸检测结果:{}", JSONObject.toJSONString(result));
|
||||
BufferedImage image = ImageIO.read(input);
|
||||
//创建保存路径
|
||||
Path imagePath = Paths.get("output").resolve("retinaface_detected.jpg");
|
||||
//绘制人脸框
|
||||
ImageUtils.drawBoundingBoxes(image, result, imagePath.toAbsolutePath().toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,7 +163,8 @@ public class FaceDemo {
|
||||
}
|
||||
|
||||
/**
|
||||
* 人脸特征提取及比对
|
||||
* seetaface6人脸特征提取及比对(可人证核验)
|
||||
* 目前仅支持windows 64位系统,如需支持其他操作系统可参考方法:featureExtractionAndCompare2
|
||||
*/
|
||||
public static void featureExtractionAndCompare(){
|
||||
try {
|
||||
@@ -180,8 +180,12 @@ public class FaceDemo {
|
||||
//提取图像中最大人脸的特征
|
||||
float[] feature1 = currentAlgorithm.featureExtraction("src/main/resources/kana1.jpg");
|
||||
float[] feature2 = currentAlgorithm.featureExtraction("src/main/resources/kana2.jpg");
|
||||
float similar = currentAlgorithm.calculSimilar(feature1, feature2);
|
||||
log.info("相似度:{}", similar);
|
||||
if(feature1 != null && feature2 != null){
|
||||
float similar = currentAlgorithm.calculSimilar(feature1, feature2);
|
||||
log.info("相似度:{}", similar);
|
||||
}else{
|
||||
log.warn("人脸特征提取失败");
|
||||
}
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
@@ -189,8 +193,31 @@ public class FaceDemo {
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册人脸及搜索人脸(1:N)
|
||||
* facenet-pytorch 人脸特征提取及比对(可人证核验)
|
||||
* 支持windows,linux,macos
|
||||
*/
|
||||
public static void featureExtractionAndCompare2(){
|
||||
try {
|
||||
//创建脸算法
|
||||
FaceAlgorithm featureAlgorithm = FaceAlgorithmFactory.createFaceFeatureAlgorithm();
|
||||
//提取身份证人脸特征
|
||||
float[] feature1 = featureAlgorithm.featureExtraction("src/main/resources/kana1.jpg");
|
||||
float[] feature2 = featureAlgorithm.featureExtraction("src/main/resources/kana2.jpg");
|
||||
if (feature1 != null && feature2 != null) {
|
||||
//相似度在0.8至0.85及以上时,可判定为同一人,但具体阈值可能因图片而异,存在一定误差。
|
||||
float similar = featureAlgorithm.calculSimilar(feature1, feature2);
|
||||
log.info("相似度:{}", similar);
|
||||
} else {
|
||||
log.warn("人脸特征提取失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册人脸及搜索人脸(1:N)
|
||||
*/
|
||||
public static void registerAndSearchFace(){
|
||||
try {
|
||||
// 初始化配置
|
||||
@@ -248,5 +275,4 @@ public class FaceDemo {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
6
pom.xml
6
pom.xml
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>ink.numberone</groupId>
|
||||
<artifactId>smartjavaai-parent</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>1.0.6</version>
|
||||
<packaging>pom</packaging>
|
||||
<description>SmartJavaAI</description>
|
||||
<modules>
|
||||
@@ -35,13 +35,13 @@
|
||||
<dependency>
|
||||
<groupId>ink.numberone</groupId>
|
||||
<artifactId>smartjavaai-common</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>1.0.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ink.numberone</groupId>
|
||||
<artifactId>smartjavaai-face</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>1.0.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>ink.numberone</groupId>
|
||||
<artifactId>smartjavaai-parent</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>1.0.6</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>smartjavaai-common</artifactId>
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<parent>
|
||||
<groupId>ink.numberone</groupId>
|
||||
<artifactId>smartjavaai-parent</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>1.0.6</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>smartjavaai-face</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>1.0.6</version>
|
||||
<name>smartjavaai-face</name>
|
||||
<description>SmartJavaAI</description>
|
||||
<url>https://github.com/geekwenjie/SmartJavaAI</url>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.smartjavaai.face.algo;
|
||||
|
||||
import ai.djl.Device;
|
||||
import ai.djl.inference.Predictor;
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.ImageFactory;
|
||||
@@ -14,6 +15,7 @@ import cn.smartjavaai.face.AbstractFaceAlgorithm;
|
||||
import cn.smartjavaai.face.FaceDetectedResult;
|
||||
import cn.smartjavaai.face.FaceDetectionTranslator;
|
||||
import cn.smartjavaai.face.ModelConfig;
|
||||
import cn.smartjavaai.face.translator.FaceFeatureTranslator;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
@@ -50,32 +52,34 @@ public class FeatureExtractionAlgo extends AbstractFaceAlgorithm {
|
||||
* 加载人脸特征提取模型
|
||||
* @param config
|
||||
* @throws Exception
|
||||
*//*
|
||||
*/
|
||||
@Override
|
||||
public void loadFaceFeatureModel(ModelConfig config) throws Exception {
|
||||
String normalize = mean.stream().map(Object::toString).collect(Collectors.joining(","));
|
||||
faceFeatureCriteria = Criteria.builder()
|
||||
faceFeatureCriteria =
|
||||
Criteria.builder()
|
||||
.setTypes(Image.class, float[].class)
|
||||
.optModelName("face_feature") // specify model file prefix
|
||||
.optModelUrls(StringUtils.isNotBlank(config.getModelPath()) ? null :
|
||||
"https://resources.djl.ai/test-models/pytorch/face_feature.zip")
|
||||
.optModelPath(StringUtils.isNotBlank(config.getModelPath()) ? Paths.get(config.getModelPath()) : null)
|
||||
.optModelName("face_feature") // specify model file prefix
|
||||
.optTranslator(new FaceFeatureTranslator())
|
||||
.optArgument("normalize", normalize)
|
||||
.optTranslatorFactory(new ImageFeatureExtractorFactory())
|
||||
.optProgress(new ProgressBar())
|
||||
.optEngine("PyTorch") // Use PyTorch engine
|
||||
.optProgress(new ProgressBar())
|
||||
.build();
|
||||
|
||||
model = faceFeatureCriteria.loadModel();
|
||||
predictor = model.newPredictor();
|
||||
}
|
||||
|
||||
|
||||
*//**
|
||||
/**
|
||||
* 特征提取
|
||||
* @param imagePath 图片路径
|
||||
* @return
|
||||
* @throws Exception
|
||||
*//*
|
||||
*/
|
||||
@Override
|
||||
public float[] featureExtraction(String imagePath) throws Exception {
|
||||
Path imageFile = Paths.get(imagePath);
|
||||
@@ -84,12 +88,12 @@ public class FeatureExtractionAlgo extends AbstractFaceAlgorithm {
|
||||
return predictor.predict(img);
|
||||
}
|
||||
|
||||
*//**
|
||||
/**
|
||||
* 特征提取
|
||||
* @param inputStream 输入流
|
||||
* @return
|
||||
* @throws Exception
|
||||
*//*
|
||||
*/
|
||||
@Override
|
||||
public float[] featureExtraction(InputStream inputStream) throws Exception {
|
||||
Image img = ImageFactory.getInstance().fromInputStream(inputStream);
|
||||
@@ -97,13 +101,13 @@ public class FeatureExtractionAlgo extends AbstractFaceAlgorithm {
|
||||
return predictor.predict(img);
|
||||
}
|
||||
|
||||
*//**
|
||||
/**
|
||||
* 计算相似度
|
||||
* @param feature1 图1特征
|
||||
* @param feature2 图2特征
|
||||
* @return
|
||||
* @throws Exception
|
||||
*//*
|
||||
*/
|
||||
@Override
|
||||
public float calculSimilar(float[] feature1, float[] feature2) throws Exception {
|
||||
float ret = 0.0f;
|
||||
@@ -118,13 +122,13 @@ public class FeatureExtractionAlgo extends AbstractFaceAlgorithm {
|
||||
return (float) ((ret / Math.sqrt(mod1) / Math.sqrt(mod2) + 1) / 2.0f);
|
||||
}
|
||||
|
||||
*//**
|
||||
/**
|
||||
* 特征比较
|
||||
* @param imagePath1 图1路径
|
||||
* @param imagePath2 图2路径
|
||||
* @return
|
||||
* @throws Exception
|
||||
*//*
|
||||
*/
|
||||
@Override
|
||||
public float featureComparison(String imagePath1, String imagePath2) throws Exception {
|
||||
float[] feature1 = featureExtraction(imagePath1);
|
||||
@@ -132,19 +136,19 @@ public class FeatureExtractionAlgo extends AbstractFaceAlgorithm {
|
||||
return calculSimilar(feature1, feature2);
|
||||
}
|
||||
|
||||
*//**
|
||||
/**
|
||||
* 特征比较
|
||||
* @param inputStream1 图1输入流
|
||||
* @param inputStream2 图2输入流
|
||||
* @return
|
||||
* @throws Exception
|
||||
*//*
|
||||
*/
|
||||
@Override
|
||||
public float featureComparison(InputStream inputStream1, InputStream inputStream2) throws Exception {
|
||||
float[] feature1 = featureExtraction(inputStream1);
|
||||
float[] feature2 = featureExtraction(inputStream2);
|
||||
return calculSimilar(feature1, feature2);
|
||||
}*/
|
||||
}
|
||||
|
||||
/*@Override
|
||||
public float[] recognize(FaceRegion region) {
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package cn.smartjavaai.face.translator;
|
||||
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.transform.Normalize;
|
||||
import ai.djl.modality.cv.transform.Resize;
|
||||
import ai.djl.modality.cv.transform.ToTensor;
|
||||
import ai.djl.ndarray.NDArray;
|
||||
import ai.djl.ndarray.NDList;
|
||||
import ai.djl.translate.Batchifier;
|
||||
import ai.djl.translate.Pipeline;
|
||||
import ai.djl.translate.Translator;
|
||||
import ai.djl.translate.TranslatorContext;
|
||||
|
||||
/**
|
||||
* @author 邓文杰
|
||||
* @date 2025/3/31
|
||||
*/
|
||||
public final class FaceFeatureTranslator implements Translator<Image, float[]> {
|
||||
|
||||
public FaceFeatureTranslator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public NDList processInput(TranslatorContext ctx, Image input) {
|
||||
NDArray array = input.toNDArray(ctx.getNDManager(), Image.Flag.COLOR);
|
||||
Pipeline pipeline = new Pipeline();
|
||||
pipeline
|
||||
.add(new Resize(180))
|
||||
.add(new ToTensor())
|
||||
.add(new Normalize(
|
||||
new float[]{127.5f / 255.0f, 127.5f / 255.0f, 127.5f / 255.0f},
|
||||
new float[]{128.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f}));
|
||||
|
||||
return pipeline.transform(new NDList(array));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public float[] processOutput(TranslatorContext ctx, NDList list) {
|
||||
return list.singletonOrThrow().toFloatArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Batchifier getBatchifier() {
|
||||
return Batchifier.STACK;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
package com.seetaface;
|
||||
|
||||
|
||||
import jdk.dynalink.linker.support.Lookup;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
@@ -19,9 +23,10 @@ public class NativeLoader {
|
||||
|
||||
|
||||
private static Path tempNativeDir;
|
||||
private static final String[] WIN_LIBS = {"tennis","tennis_haswell","tennis_pentium","tennis_sandy_bridge","SeetaAuthorize","SeetaFaceAntiSpoofingX600","SeetaFaceDetector600","SeetaFaceLandmarker600","SeetaFaceRecognizer610","SeetaFace6JNI"};
|
||||
private static final String[] LINUX_CENTOS_LIBS = {"libmain.so"};
|
||||
private static final String[] LINUX_UBUNTU_LIBS = {"libdependency1.so", "libdependency2.so", "libmain.so"};
|
||||
private static final String[] WIN_LIBS = {"tennis.dll","tennis_haswell.dll","tennis_pentium.dll","tennis_sandy_bridge.dll","SeetaAuthorize.dll","SeetaFaceAntiSpoofingX600.dll","SeetaFaceDetector600.dll","SeetaFaceLandmarker600.dll","SeetaFaceRecognizer610.dll","SeetaFace6JNI.dll"};
|
||||
//private static final String[] WIN_LIBS = {"tennis","tennis_haswell","tennis_pentium","tennis_sandy_bridge","SeetaAuthorize","SeetaFaceAntiSpoofingX600","SeetaFaceDetector600","SeetaFaceLandmarker600","SeetaFaceRecognizer610","SeetaFace6JNI"};
|
||||
private static final String[] LINUX_CENTOS_LIBS = {"libSeetaAuthorize.so","libtennis.so","libtennis_haswell.so","libtennis_pentium.so","libtennis_sandy_bridge.so","libSeetaFaceDetector600.so","libSeetaAgePredictor600.so","libSeetaEyeStateDetector200.so","libSeetaFaceAntiSpoofingX600.so","libSeetaFaceLandmarker600.so","libSeetaFaceRecognizer610.so","libSeetaGenderPredictor600.so","libSeetaMaskDetector200.so","libSeetaPoseEstimation600.so","libSeetaFaceTracking600.so","libSeetaQualityAssessor300.so"};
|
||||
private static final String[] LINUX_UBUNTU_LIBS = {"libSeetaAuthorize.so","libtennis.so","libtennis_haswell.so","libtennis_pentium.so","libtennis_sandy_bridge.so","libSeetaFaceDetector600.so","libSeetaAgePredictor600.so","libSeetaEyeStateDetector200.so","libSeetaFaceAntiSpoofingX600.so","libSeetaFaceLandmarker600.so","libSeetaFaceRecognizer610.so","libSeetaGenderPredictor600.so","libSeetaMaskDetector200.so","libSeetaPoseEstimation600.so","libSeetaFaceTracking600.so","libSeetaQualityAssessor300.so"};
|
||||
|
||||
private static final String TEMP_DIR = "smartjavaai-native-libs";
|
||||
|
||||
@@ -51,18 +56,12 @@ public class NativeLoader {
|
||||
} else {
|
||||
System.setProperty("java.library.path", sysLib + separator + tempNativeDir);
|
||||
}
|
||||
try {
|
||||
//使java.library.path生效
|
||||
Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
|
||||
sysPathsField.setAccessible(true);
|
||||
sysPathsField.set(null, null);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
// 按顺序加载库(确保依赖关系)
|
||||
for (String libName : libNames) {
|
||||
System.loadLibrary(libName);
|
||||
log.info("Loading library: " + tempNativeDir + File.separator + libName);
|
||||
System.load(tempNativeDir + File.separator + libName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Native library loading failed", e);
|
||||
@@ -84,7 +83,7 @@ public class NativeLoader {
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void extractLibrary(String libName,String libDir) throws IOException {
|
||||
String resourcePath = "/native" + libDir + "/" + libName + ".dll";
|
||||
String resourcePath = "/native" + libDir + "/" + libName;
|
||||
try (InputStream in = NativeLoader.class.getResourceAsStream(resourcePath)) {
|
||||
if (in == null) throw new FileNotFoundException(resourcePath);
|
||||
|
||||
@@ -107,7 +106,7 @@ public class NativeLoader {
|
||||
String osName = System.getProperty("os.name").toLowerCase();
|
||||
if (osName.contains("win")) {
|
||||
return "/windows";
|
||||
} else if (osName.contains("linux")) {
|
||||
} /*else if (osName.contains("linux")) {
|
||||
String linuxOsName = getLinuxOsName();
|
||||
if(StringUtils.isBlank(linuxOsName)){
|
||||
throw new UnsupportedOperationException("Unsupported platform");
|
||||
@@ -117,7 +116,7 @@ public class NativeLoader {
|
||||
}else if(linuxOsName.contains("centos")){
|
||||
return "/linux/centos";
|
||||
}
|
||||
}
|
||||
}*/
|
||||
throw new UnsupportedOperationException("Unsupported platform");
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>ink.numberone</groupId>
|
||||
<artifactId>smartjavaai-parent</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>1.0.6</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>smartjavaai-seetaface6-lib</artifactId>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user