diff --git a/README.md b/README.md index dcab9b4..5da7e3f 100644 --- a/README.md +++ b/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 @@ ink.numberone smartjavaai-face - 1.0.5 + 1.0.6 ``` @@ -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高版本 + + + diff --git a/examples/pom.xml b/examples/pom.xml index 1fab46c..ea30c65 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -43,7 +43,7 @@ ink.numberone smartjavaai-face - 1.0.5 + 1.0.6 diff --git a/examples/src/main/java/smartai/examples/face/FaceDemo.java b/examples/src/main/java/smartai/examples/face/FaceDemo.java index c0897d2..431344d 100644 --- a/examples/src/main/java/smartai/examples/face/FaceDemo.java +++ b/examples/src/main/java/smartai/examples/face/FaceDemo.java @@ -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 { } } - } diff --git a/pom.xml b/pom.xml index 6b8c658..97803f1 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ink.numberone smartjavaai-parent - 1.0.5 + 1.0.6 pom SmartJavaAI @@ -35,13 +35,13 @@ ink.numberone smartjavaai-common - 1.0.5 + 1.0.6 ink.numberone smartjavaai-face - 1.0.5 + 1.0.6 diff --git a/smartjavaai-common/pom.xml b/smartjavaai-common/pom.xml index 8bcfa07..bffeb9b 100644 --- a/smartjavaai-common/pom.xml +++ b/smartjavaai-common/pom.xml @@ -6,7 +6,7 @@ ink.numberone smartjavaai-parent - 1.0.5 + 1.0.6 smartjavaai-common diff --git a/smartjavaai-face/pom.xml b/smartjavaai-face/pom.xml index cb1e0d2..0f22a62 100644 --- a/smartjavaai-face/pom.xml +++ b/smartjavaai-face/pom.xml @@ -6,11 +6,11 @@ ink.numberone smartjavaai-parent - 1.0.5 + 1.0.6 smartjavaai-face - 1.0.5 + 1.0.6 smartjavaai-face SmartJavaAI https://github.com/geekwenjie/SmartJavaAI diff --git a/smartjavaai-face/src/main/java/cn/smartjavaai/face/algo/FeatureExtractionAlgo.java b/smartjavaai-face/src/main/java/cn/smartjavaai/face/algo/FeatureExtractionAlgo.java index 9b10373..734474c 100644 --- a/smartjavaai-face/src/main/java/cn/smartjavaai/face/algo/FeatureExtractionAlgo.java +++ b/smartjavaai-face/src/main/java/cn/smartjavaai/face/algo/FeatureExtractionAlgo.java @@ -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) { diff --git a/smartjavaai-face/src/main/java/cn/smartjavaai/face/translator/FaceFeatureTranslator.java b/smartjavaai-face/src/main/java/cn/smartjavaai/face/translator/FaceFeatureTranslator.java new file mode 100644 index 0000000..ec2d430 --- /dev/null +++ b/smartjavaai-face/src/main/java/cn/smartjavaai/face/translator/FaceFeatureTranslator.java @@ -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 { + + 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; + } +} diff --git a/smartjavaai-face/src/main/java/com/seetaface/NativeLoader.java b/smartjavaai-face/src/main/java/com/seetaface/NativeLoader.java index ad2d7dc..0e60b46 100644 --- a/smartjavaai-face/src/main/java/com/seetaface/NativeLoader.java +++ b/smartjavaai-face/src/main/java/com/seetaface/NativeLoader.java @@ -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"); } diff --git a/smartjavaai-seetaface6-lib/pom.xml b/smartjavaai-seetaface6-lib/pom.xml index 369977a..de5d13e 100644 --- a/smartjavaai-seetaface6-lib/pom.xml +++ b/smartjavaai-seetaface6-lib/pom.xml @@ -6,7 +6,7 @@ ink.numberone smartjavaai-parent - 1.0.5 + 1.0.6 smartjavaai-seetaface6-lib diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaAgePredictor600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaAgePredictor600.so deleted file mode 100644 index cee2324..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaAgePredictor600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaAuthorize.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaAuthorize.so deleted file mode 100644 index 2560a78..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaAuthorize.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaEyeStateDetector200.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaEyeStateDetector200.so deleted file mode 100644 index 862b21a..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaEyeStateDetector200.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceAntiSpoofingX600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceAntiSpoofingX600.so deleted file mode 100644 index da0d784..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceAntiSpoofingX600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceDetector600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceDetector600.so deleted file mode 100644 index 501087e..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceDetector600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceLandmarker600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceLandmarker600.so deleted file mode 100644 index e3263c7..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceLandmarker600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceRecognizer610.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceRecognizer610.so deleted file mode 100644 index c023622..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceRecognizer610.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceTracking600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceTracking600.so deleted file mode 100644 index 93265fa..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaFaceTracking600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaGenderPredictor600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaGenderPredictor600.so deleted file mode 100644 index e23969f..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaGenderPredictor600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaMaskDetector200.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaMaskDetector200.so deleted file mode 100644 index dce9f73..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaMaskDetector200.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaPoseEstimation600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaPoseEstimation600.so deleted file mode 100644 index bd17c6d..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaPoseEstimation600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaQualityAssessor300.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaQualityAssessor300.so deleted file mode 100644 index 6a1f8a0..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libSeetaQualityAssessor300.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libtennis.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libtennis.so deleted file mode 100644 index 06fee2b..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libtennis.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libtennis_haswell.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libtennis_haswell.so deleted file mode 100644 index 3e357d0..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libtennis_haswell.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libtennis_pentium.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libtennis_pentium.so deleted file mode 100644 index f60e405..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libtennis_pentium.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libtennis_sandy_bridge.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libtennis_sandy_bridge.so deleted file mode 100644 index 3a0474d..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/centos/libtennis_sandy_bridge.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaAgePredictor600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaAgePredictor600.so deleted file mode 100644 index 0e489bd..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaAgePredictor600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaAuthorize.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaAuthorize.so deleted file mode 100644 index 446a8ad..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaAuthorize.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaEyeStateDetector200.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaEyeStateDetector200.so deleted file mode 100644 index 7d74b9e..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaEyeStateDetector200.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceAntiSpoofingX600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceAntiSpoofingX600.so deleted file mode 100644 index 128751e..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceAntiSpoofingX600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceDetector600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceDetector600.so deleted file mode 100644 index 52307f0..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceDetector600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceLandmarker600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceLandmarker600.so deleted file mode 100644 index 92f230e..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceLandmarker600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceRecognizer610.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceRecognizer610.so deleted file mode 100644 index d967d29..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceRecognizer610.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceTracking600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceTracking600.so deleted file mode 100644 index bc647bf..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaFaceTracking600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaGenderPredictor600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaGenderPredictor600.so deleted file mode 100644 index 9a26839..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaGenderPredictor600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaMaskDetector200.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaMaskDetector200.so deleted file mode 100644 index a894911..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaMaskDetector200.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaPoseEstimation600.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaPoseEstimation600.so deleted file mode 100644 index 0730ebf..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaPoseEstimation600.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaQualityAssessor300.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaQualityAssessor300.so deleted file mode 100644 index 0e6b50d..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libSeetaQualityAssessor300.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libtennis.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libtennis.so deleted file mode 100644 index 37c2c3e..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libtennis.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libtennis_haswell.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libtennis_haswell.so deleted file mode 100644 index 4a7c4d3..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libtennis_haswell.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libtennis_pentium.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libtennis_pentium.so deleted file mode 100644 index 6bab905..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libtennis_pentium.so and /dev/null differ diff --git a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libtennis_sandy_bridge.so b/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libtennis_sandy_bridge.so deleted file mode 100644 index 3fcc830..0000000 Binary files a/smartjavaai-seetaface6-lib/src/main/resources/native/linux/ubuntu/libtennis_sandy_bridge.so and /dev/null differ