1、集成车牌识别模型,支持车牌检测与识别

2、新增 Milvus 身份验证支持
3、目标检测功能升级:可指定类别及topk
4、支持自定义线程池线程数量
This commit is contained in:
dengwenjie
2025-07-28 12:04:02 +08:00
parent 1bd74d1bb8
commit 1d45bc597d
117 changed files with 3490 additions and 437 deletions

View File

@@ -1,5 +1,6 @@
package cn.smartjavaai.face.config;
import cn.smartjavaai.common.config.ModelConfig;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.face.enums.FaceAttributeModelEnum;
import lombok.Data;
@@ -9,7 +10,7 @@ import lombok.Data;
* @author dwj
*/
@Data
public class FaceAttributeConfig {
public class FaceAttributeConfig extends ModelConfig {
/**
* 人脸属性识别模型枚举
@@ -21,16 +22,6 @@ public class FaceAttributeConfig {
*/
private String modelPath;
/**
* 设备类型
*/
private DeviceEnum device;
/**
* gpu设备ID 当device为GPU时生效
*/
private int gpuId = 0;
/**
* 是否启用年龄检测
*/

View File

@@ -1,5 +1,6 @@
package cn.smartjavaai.face.config;
import cn.smartjavaai.common.config.ModelConfig;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.face.constant.FaceDetectConstant;
import cn.smartjavaai.face.enums.FaceDetModelEnum;
@@ -13,7 +14,7 @@ import java.util.Map;
* @author dwj
*/
@Data
public class FaceDetConfig {
public class FaceDetConfig extends ModelConfig {
/**
* 人脸检测模型枚举
@@ -36,16 +37,6 @@ public class FaceDetConfig {
*/
private String modelPath;
/**
* 设备类型
*/
private DeviceEnum device;
/**
* 个性化配置(按模型类型动态解析)
*/
private Map<String, Object> customParams = new HashMap<>();
public FaceDetConfig() {
}
@@ -59,19 +50,4 @@ public class FaceDetConfig {
this.modelPath = modelPath;
}
public <T> T getCustomParam(String key, Class<T> clazz) {
Object value = customParams.get(key);
if (value == null) return null;
return clazz.cast(value);
}
/**
* 添加个性化配置项
*/
public void putCustomParam(String key, Object value) {
if (customParams == null) {
customParams = new HashMap<>();
}
customParams.put(key, value);
}
}

View File

@@ -1,5 +1,6 @@
package cn.smartjavaai.face.config;
import cn.smartjavaai.common.config.ModelConfig;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.face.enums.ExpressionModelEnum;
import cn.smartjavaai.face.model.facedect.FaceDetModel;
@@ -14,7 +15,7 @@ import java.util.Map;
* @date 2025/7/1
*/
@Data
public class FaceExpressionConfig {
public class FaceExpressionConfig extends ModelConfig {
/**
* 模型枚举
@@ -26,11 +27,6 @@ public class FaceExpressionConfig {
*/
private String modelPath;
/**
* 设备类型
*/
private DeviceEnum device;
/**
* 人脸检测模型
*/

View File

@@ -1,5 +1,6 @@
package cn.smartjavaai.face.config;
import cn.smartjavaai.common.config.ModelConfig;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.face.constant.FaceDetectConstant;
import cn.smartjavaai.face.enums.FaceRecModelEnum;
@@ -16,7 +17,7 @@ import java.util.Map;
* @author dwj
*/
@Data
public class FaceRecConfig {
public class FaceRecConfig extends ModelConfig {
/**
* 人脸模型枚举
@@ -28,11 +29,6 @@ public class FaceRecConfig {
*/
private String modelPath;
/**
* 设备类型
*/
private DeviceEnum device;
/**
* 向量数据库配置
@@ -60,10 +56,6 @@ public class FaceRecConfig {
*/
private FaceDetModel detectModel;
/**
* 个性化配置(按模型类型动态解析)
*/
private Map<String, Object> customParams = new HashMap<>();
public FaceRecConfig() {
}
@@ -77,19 +69,5 @@ public class FaceRecConfig {
this.modelPath = modelPath;
}
public <T> T getCustomParam(String key, Class<T> clazz) {
Object value = customParams.get(key);
if (value == null) return null;
return clazz.cast(value);
}
/**
* 添加个性化配置项
*/
public void putCustomParam(String key, Object value) {
if (customParams == null) {
customParams = new HashMap<>();
}
customParams.put(key, value);
}
}

View File

@@ -1,5 +1,6 @@
package cn.smartjavaai.face.config;
import cn.smartjavaai.common.config.ModelConfig;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.face.constant.LivenessConstant;
import cn.smartjavaai.face.enums.LivenessModelEnum;
@@ -15,7 +16,7 @@ import java.util.Map;
* @author dwj
*/
@Data
public class LivenessConfig {
public class LivenessConfig extends ModelConfig {
/**
* 活体检测模型枚举
@@ -27,20 +28,12 @@ public class LivenessConfig {
*/
private String modelPath;
/**
* 设备类型
*/
private DeviceEnum device;
/**
* 人脸检测模型
*/
private FaceDetModel detectModel;
/**
* 个性化配置(按模型类型动态解析)
*/
private Map<String, Object> customParams = new HashMap<>();
/**
@@ -74,20 +67,4 @@ public class LivenessConfig {
this.modelPath = modelPath;
}
// 可选封装方法,便于类型转换和调用
public <T> T getCustomParam(String key, Class<T> clazz) {
Object value = customParams.get(key);
if (value == null) return null;
return clazz.cast(value);
}
/**
* 添加个性化配置项
*/
public void putCustomParam(String key, Object value) {
if (customParams == null) {
customParams = new HashMap<>();
}
customParams.put(key, value);
}
}

View File

@@ -1,5 +1,6 @@
package cn.smartjavaai.face.config;
import cn.smartjavaai.common.config.ModelConfig;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.face.constant.LivenessConstant;
import cn.smartjavaai.face.enums.LivenessModelEnum;
@@ -11,7 +12,7 @@ import lombok.Data;
* @author dwj
*/
@Data
public class QualityConfig {
public class QualityConfig extends ModelConfig {
/**
* 活体检测模型枚举
@@ -23,16 +24,6 @@ public class QualityConfig {
*/
private String modelPath;
/**
* 设备类型
*/
private DeviceEnum device;
/**
* gpu设备ID 当device为GPU时生效
*/
private int gpuId = 0;
public QualityConfig() {
}

View File

@@ -1,5 +1,6 @@
package cn.smartjavaai.face.model.attribute;
import ai.djl.engine.Engine;
import cn.smartjavaai.common.entity.*;
import cn.smartjavaai.common.entity.face.FaceAttribute;
import cn.smartjavaai.common.entity.face.FaceInfo;
@@ -102,6 +103,19 @@ public class Seetaface6FaceAttributeModel implements FaceAttributeModel {
this.eyeStateDetectorPool = new EyeStateDetectorPool(eyeStateDetectorPoolConfSetting);
this.maskDetectorPool = new MaskDetectorPool(maskDetectorPoolConfSetting);
this.poseEstimatorPool = new PoseEstimatorPool(poseEstimatorPoolConfSetting);
int predictorPoolSize = config.getPredictorPoolSize();
if(config.getPredictorPoolSize() <= 0){
predictorPoolSize = Runtime.getRuntime().availableProcessors(); // 默认等于CPU核心数
}
faceDetectorPool.setMaxTotal(predictorPoolSize);
faceLandmarkerPool.setMaxTotal(predictorPoolSize);
genderPredictorPool.setMaxTotal(predictorPoolSize);
agePredictorPool.setMaxTotal(predictorPoolSize);
eyeStateDetectorPool.setMaxTotal(predictorPoolSize);
maskDetectorPool.setMaxTotal(predictorPoolSize);
poseEstimatorPool.setMaxTotal(predictorPoolSize);
log.debug("模型推理器线程池最大数量: " + predictorPoolSize);
} catch (FileNotFoundException e) {
throw new FaceException(e);
}
@@ -471,6 +485,35 @@ public class Seetaface6FaceAttributeModel implements FaceAttributeModel {
}
}
public FaceDetectorPool getFaceDetectorPool() {
return faceDetectorPool;
}
public GenderPredictorPool getGenderPredictorPool() {
return genderPredictorPool;
}
public FaceLandmarkerPool getFaceLandmarkerPool() {
return faceLandmarkerPool;
}
public AgePredictorPool getAgePredictorPool() {
return agePredictorPool;
}
public EyeStateDetectorPool getEyeStateDetectorPool() {
return eyeStateDetectorPool;
}
public MaskDetectorPool getMaskDetectorPool() {
return maskDetectorPool;
}
public PoseEstimatorPool getPoseEstimatorPool() {
return poseEstimatorPool;
}
@Override
public void close() throws Exception {
if(Objects.nonNull(faceDetectorPool)){

View File

@@ -2,6 +2,7 @@ package cn.smartjavaai.face.model.expression;
import ai.djl.Device;
import ai.djl.MalformedModelException;
import ai.djl.engine.Engine;
import ai.djl.inference.Predictor;
import ai.djl.modality.Classifications;
import ai.djl.modality.cv.Image;
@@ -32,6 +33,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.opencv.core.Mat;
import org.opencv.face.Face;
import javax.imageio.ImageIO;
@@ -56,7 +58,7 @@ public class CommonEmotionModel implements ExpressionModel{
private ZooModel<Image, Classifications> model;
private ObjectPool<Predictor<Image, Classifications>> predictorPool;
private GenericObjectPool<Predictor<Image, Classifications>> predictorPool;
@Override
public void loadModel(FaceExpressionConfig config) {
@@ -73,6 +75,14 @@ public class CommonEmotionModel implements ExpressionModel{
try {
model = criteria.loadModel();
this.predictorPool = new GenericObjectPool<>(new PredictorFactory<>(model));
int predictorPoolSize = config.getPredictorPoolSize();
if(config.getPredictorPoolSize() <= 0){
predictorPoolSize = Runtime.getRuntime().availableProcessors(); // 默认等于CPU核心数
}
predictorPool.setMaxTotal(predictorPoolSize);
log.debug("当前设备: " + model.getNDManager().getDevice());
log.debug("当前引擎: " + Engine.getInstance().getEngineName());
log.debug("模型推理器线程池最大数量: " + predictorPoolSize);
} catch (IOException | ModelNotFoundException | MalformedModelException e) {
throw new FaceException("DenseNetEmotionModel模型加载失败", e);
}
@@ -153,6 +163,7 @@ public class CommonEmotionModel implements ExpressionModel{
result.setClassifications(classifications);
faceInfo.setExpressionResult(result);
}
((Mat)djlImage.getWrappedImage()).release();
return faceDetectionResponse;
}
@@ -226,6 +237,7 @@ public class CommonEmotionModel implements ExpressionModel{
result.setClassifications(classifications);
expressionResults.add(result);
}
((Mat)djlImage.getWrappedImage()).release();
return R.ok(expressionResults);
}
@@ -276,6 +288,7 @@ public class CommonEmotionModel implements ExpressionModel{
FacialExpression expression = FacialExpression.fromLabel(bestClass.getClassName());
ExpressionResult result = new ExpressionResult(expression, (float)bestClass.getProbability());
result.setClassifications(classifications);
((Mat)djlImage.getWrappedImage()).release();
return R.ok(result);
}
@@ -342,7 +355,10 @@ public class CommonEmotionModel implements ExpressionModel{
return detectTopFace(imageData);
}
@Override
public GenericObjectPool<Predictor<Image, Classifications>> getPool() {
return predictorPool;
}
@Override
public void close() {

View File

@@ -1,11 +1,16 @@
package cn.smartjavaai.face.model.expression;
import ai.djl.inference.Predictor;
import ai.djl.modality.Classifications;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.output.DetectedObjects;
import cn.smartjavaai.common.entity.DetectionRectangle;
import cn.smartjavaai.common.entity.DetectionResponse;
import cn.smartjavaai.common.entity.Point;
import cn.smartjavaai.common.entity.R;
import cn.smartjavaai.common.entity.face.ExpressionResult;
import cn.smartjavaai.face.config.FaceExpressionConfig;
import org.apache.commons.pool2.impl.GenericObjectPool;
import java.awt.image.BufferedImage;
import java.util.List;
@@ -190,6 +195,9 @@ public interface ExpressionModel extends AutoCloseable{
default GenericObjectPool<Predictor<Image, Classifications>> getPool(){
throw new UnsupportedOperationException("默认不支持该功能");
}
}

View File

@@ -26,7 +26,7 @@ public class EmotionCriteriaFactory {
public static Criteria<Image, Classifications> createCriteria(FaceExpressionConfig config) {
Device device = null;
if(!Objects.isNull(config.getDevice())){
device = config.getDevice() == DeviceEnum.CPU ? Device.cpu() : Device.gpu();
device = config.getDevice() == DeviceEnum.CPU ? Device.cpu() : Device.gpu(config.getGpuId());
}
Criteria<Image, Classifications> criteria = null;
if(config.getModelEnum() == ExpressionModelEnum.DensNet121){
@@ -50,6 +50,7 @@ public class EmotionCriteriaFactory {
.optModelPath(Paths.get(config.getModelPath()))
.optTranslator(new FrEmotionTranslator(224))
.optProgress(new ProgressBar())
.optDevice(device)
.build();
}
return criteria;

View File

@@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.opencv.core.Mat;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
@@ -43,7 +44,7 @@ import java.util.Objects;
@Slf4j
public class CommonFaceDetModel implements FaceDetModel{
private ObjectPool<Predictor<Image, DetectedObjects>> predictorPool;
private GenericObjectPool<Predictor<Image, DetectedObjects>> predictorPool;
private ZooModel<Image, DetectedObjects> model;
@@ -58,8 +59,14 @@ public class CommonFaceDetModel implements FaceDetModel{
try {
model = criteria.loadModel();
this.predictorPool = new GenericObjectPool<>(new PredictorFactory<>(model));
int predictorPoolSize = config.getPredictorPoolSize();
if(config.getPredictorPoolSize() <= 0){
predictorPoolSize = Runtime.getRuntime().availableProcessors(); // 默认等于CPU核心数
}
predictorPool.setMaxTotal(predictorPoolSize);
log.debug("当前设备: " + model.getNDManager().getDevice());
log.debug("当前引擎: " + Engine.getInstance().getEngineName());
log.debug("模型推理器线程池最大数量: " + predictorPoolSize);
} catch (IOException | ModelNotFoundException | MalformedModelException e) {
throw new FaceException("人脸检测模型加载失败", e);
}
@@ -81,11 +88,16 @@ public class CommonFaceDetModel implements FaceDetModel{
Image img = null;
try {
img = ImageFactory.getInstance().fromFile(Paths.get(imagePath));
DetectedObjects detection = detect(img);
return R.ok(FaceUtils.convertToDetectionResponse(detection,img));
} catch (IOException e) {
throw new FaceException("无效的图片", e);
} finally {
if (img != null) {
((Mat)img.getWrappedImage()).release();
}
}
DetectedObjects detection = detect(img);
return R.ok(FaceUtils.convertToDetectionResponse(detection,img));
}
/**
@@ -99,12 +111,17 @@ public class CommonFaceDetModel implements FaceDetModel{
if(Objects.isNull(imageInputStream)){
return R.fail(R.Status.INVALID_IMAGE);
}
Image img = null;
try {
Image img = ImageFactory.getInstance().fromInputStream(imageInputStream);
img = ImageFactory.getInstance().fromInputStream(imageInputStream);
DetectedObjects detection = detect(img);
return R.ok(FaceUtils.convertToDetectionResponse(detection,img));
} catch (IOException e) {
throw new FaceException("无效图片输入流", e);
} finally {
if (img != null) {
((Mat)img.getWrappedImage()).release();
}
}
}
@@ -114,9 +131,19 @@ public class CommonFaceDetModel implements FaceDetModel{
if(!ImageUtils.isImageValid(image)){
return R.fail(R.Status.INVALID_IMAGE);
}
Image img = ImageFactory.getInstance().fromImage(OpenCVUtils.image2Mat(image));
DetectedObjects detection = detect(img);
return R.ok(FaceUtils.convertToDetectionResponse(detection,img));
Image img = null;
try {
img = ImageFactory.getInstance().fromImage(OpenCVUtils.image2Mat(image));
DetectedObjects detection = detect(img);
return R.ok(FaceUtils.convertToDetectionResponse(detection,img));
} catch (Exception e) {
throw new FaceException(e);
} finally {
if (img != null) {
((Mat)img.getWrappedImage()).release();
}
}
}
@Override
@@ -124,11 +151,7 @@ public class CommonFaceDetModel implements FaceDetModel{
if(Objects.isNull(imageData)){
return R.fail(R.Status.INVALID_IMAGE);
}
try {
return detect(ImageIO.read(new ByteArrayInputStream(imageData)));
} catch (IOException e) {
throw new FaceException("错误的图像", e);
}
return detect(new ByteArrayInputStream(imageData));
}
@Override
@@ -145,8 +168,9 @@ public class CommonFaceDetModel implements FaceDetModel{
if(!FileUtils.isFileExists(imagePath)){
return R.fail(R.Status.FILE_NOT_FOUND);
}
Image img = null;
try {
Image img = ImageFactory.getInstance().fromFile(Paths.get(imagePath));
img = ImageFactory.getInstance().fromFile(Paths.get(imagePath));
DetectedObjects detectedObjects = detect(img);
if(Objects.isNull(detectedObjects) || detectedObjects.getNumberOfObjects() == 0){
return R.fail(R.Status.NO_FACE_DETECTED);
@@ -158,6 +182,10 @@ public class CommonFaceDetModel implements FaceDetModel{
return R.ok();
} catch (IOException e) {
throw new FaceException(e);
} finally {
if (img != null){
((Mat)img.getWrappedImage()).release();
}
}
}
@@ -181,6 +209,10 @@ public class CommonFaceDetModel implements FaceDetModel{
return R.ok(ImageIO.read(new ByteArrayInputStream(imageBytes)));
} catch (IOException e) {
throw new FaceException("导出图片失败", e);
} finally {
if (img != null){
((Mat)img.getWrappedImage()).release();
}
}
}
@@ -213,6 +245,11 @@ public class CommonFaceDetModel implements FaceDetModel{
}
@Override
public GenericObjectPool<Predictor<Image, DetectedObjects>> getPool() {
return predictorPool;
}
@Override
public void close() {
try {

View File

@@ -1,8 +1,13 @@
package cn.smartjavaai.face.model.facedect;
import ai.djl.inference.Predictor;
import ai.djl.modality.Classifications;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.output.DetectedObjects;
import cn.smartjavaai.common.entity.DetectionResponse;
import cn.smartjavaai.common.entity.R;
import cn.smartjavaai.face.config.FaceDetConfig;
import org.apache.commons.pool2.impl.GenericObjectPool;
import java.awt.image.BufferedImage;
import java.io.InputStream;
@@ -83,6 +88,10 @@ public interface FaceDetModel extends AutoCloseable{
throw new UnsupportedOperationException("默认不支持该功能");
}
default GenericObjectPool<Predictor<Image, DetectedObjects>> getPool(){
throw new UnsupportedOperationException("默认不支持该功能");
}
}

View File

@@ -1,5 +1,6 @@
package cn.smartjavaai.face.model.facedect;
import ai.djl.engine.Engine;
import cn.smartjavaai.common.entity.DetectionResponse;
import cn.smartjavaai.common.entity.R;
import cn.smartjavaai.common.enums.DeviceEnum;
@@ -48,13 +49,9 @@ public class SeetaFace6FaceDetModel implements FaceDetModel{
String[] faceDetectorModelPath = {config.getModelPath() + File.separator + "face_detector.csta"};
String[] faceLandmarkerModelPath = {config.getModelPath() + File.separator + "face_landmarker_pts5.csta"};
SeetaDevice device = SeetaDevice.SEETA_DEVICE_AUTO;
int gpuId = 0;
int gpuId = config.getGpuId();
if(Objects.nonNull(config.getDevice())){
device = config.getDevice() == DeviceEnum.CPU ? SeetaDevice.SEETA_DEVICE_CPU : SeetaDevice.SEETA_DEVICE_GPU;
Integer gpuIdValue = config.getCustomParam("gpuId", Integer.class);
if(Objects.nonNull(gpuIdValue) && device == SeetaDevice.SEETA_DEVICE_GPU){
gpuId = gpuIdValue;
}
}
try {
SeetaModelSetting faceDetectorPoolSetting = new SeetaModelSetting(gpuId, faceDetectorModelPath, device);
@@ -65,6 +62,14 @@ public class SeetaFace6FaceDetModel implements FaceDetModel{
this.faceDetectorPool = new FaceDetectorPool(faceDetectorPoolConfSetting);
this.faceLandmarkerPool = new FaceLandmarkerPool(faceLandmarkerPoolConfSetting);
int predictorPoolSize = config.getPredictorPoolSize();
if(config.getPredictorPoolSize() <= 0){
predictorPoolSize = Runtime.getRuntime().availableProcessors(); // 默认等于CPU核心数
}
faceDetectorPool.setMaxTotal(predictorPoolSize);
faceLandmarkerPool.setMaxTotal(predictorPoolSize);
log.debug("模型推理器线程池最大数量: " + predictorPoolSize);
} catch (FileNotFoundException e) {
throw new FaceException(e);
}
@@ -212,8 +217,13 @@ public class SeetaFace6FaceDetModel implements FaceDetModel{
}
public FaceDetectorPool getFaceDetectorPool() {
return faceDetectorPool;
}
public FaceLandmarkerPool getFaceLandmarkerPool() {
return faceLandmarkerPool;
}
@Override
public void close() throws Exception {

View File

@@ -31,7 +31,7 @@ public class FaceDetCriteriaFactory {
public static Criteria<Image, DetectedObjects> createCriteria(FaceDetConfig config) {
Device device = null;
if(!Objects.isNull(config.getDevice())){
device = config.getDevice() == DeviceEnum.CPU ? Device.cpu() : Device.gpu();
device = config.getDevice() == DeviceEnum.CPU ? Device.cpu() : Device.gpu(config.getGpuId());
}
Criteria<Image, DetectedObjects> criteria = null;
if(config.getModelEnum() == FaceDetModelEnum.RETINA_FACE){

View File

@@ -9,6 +9,7 @@ import ai.djl.ndarray.NDManager;
import ai.djl.repository.zoo.Criteria;
import ai.djl.repository.zoo.ModelNotFoundException;
import ai.djl.repository.zoo.ZooModel;
import cn.hutool.core.lang.UUID;
import cn.smartjavaai.common.entity.*;
import cn.smartjavaai.common.entity.face.FaceInfo;
import cn.smartjavaai.common.entity.face.FaceSearchResult;
@@ -41,6 +42,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.opencv.core.Mat;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
@@ -68,7 +70,7 @@ public class CommonFaceRecModel implements FaceRecModel{
private static volatile boolean isLoadCompleted = false;
private ObjectPool<Predictor<Image, float[]>> predictorPool;
private GenericObjectPool<Predictor<Image, float[]>> predictorPool;
private ZooModel<Image, float[]> model;
@@ -101,8 +103,14 @@ public class CommonFaceRecModel implements FaceRecModel{
model = faceFeatureCriteria.loadModel();
// 创建池子:每个线程独享 Predictor
this.predictorPool = new GenericObjectPool<>(new PredictorFactory<>(model));
int predictorPoolSize = config.getPredictorPoolSize();
if(config.getPredictorPoolSize() <= 0){
predictorPoolSize = Runtime.getRuntime().availableProcessors(); // 默认等于CPU核心数
}
predictorPool.setMaxTotal(predictorPoolSize);
log.debug("当前设备: " + model.getNDManager().getDevice());
log.debug("当前引擎: " + Engine.getInstance().getEngineName());
log.debug("模型推理器线程池最大数量: " + predictorPoolSize);
} catch (IOException | ModelNotFoundException | MalformedModelException e) {
throw new FaceException("模型加载失败", e);
}
@@ -286,6 +294,7 @@ public class CommonFaceRecModel implements FaceRecModel{
faceInfo.setFeature(features);
}
}
((Mat)djlImage.getWrappedImage()).release();
return detectedResult;
}
@@ -350,6 +359,7 @@ public class CommonFaceRecModel implements FaceRecModel{
}
features = featureExtraction(subImage);
}
((Mat)djlImage.getWrappedImage()).release();
return Objects.isNull(features) ? R.fail(R.Status.Unknown) : R.ok(features);
}
@@ -703,5 +713,8 @@ public class CommonFaceRecModel implements FaceRecModel{
}
@Override
public GenericObjectPool<Predictor<Image, float[]>> getPool() {
return predictorPool;
}
}

View File

@@ -1,5 +1,7 @@
package cn.smartjavaai.face.model.facerec;
import ai.djl.inference.Predictor;
import ai.djl.modality.cv.Image;
import cn.smartjavaai.common.entity.DetectionResponse;
import cn.smartjavaai.common.entity.R;
import cn.smartjavaai.face.config.FaceRecConfig;
@@ -7,6 +9,7 @@ import cn.smartjavaai.face.entity.FaceRegisterInfo;
import cn.smartjavaai.face.entity.FaceSearchParams;
import cn.smartjavaai.common.entity.face.FaceSearchResult;
import cn.smartjavaai.face.vector.entity.FaceVector;
import org.apache.commons.pool2.impl.GenericObjectPool;
import java.awt.image.BufferedImage;
import java.io.InputStream;
@@ -367,4 +370,9 @@ public interface FaceRecModel extends AutoCloseable{
throw new UnsupportedOperationException("默认不支持该功能");
}
default GenericObjectPool<Predictor<Image, float[]>> getPool() {
throw new UnsupportedOperationException("默认不支持该功能");
}
}

View File

@@ -1,5 +1,6 @@
package cn.smartjavaai.face.model.facerec;
import ai.djl.engine.Engine;
import cn.smartjavaai.common.entity.DetectionInfo;
import cn.smartjavaai.common.entity.DetectionResponse;
import cn.smartjavaai.common.entity.R;
@@ -89,13 +90,9 @@ public class SeetaFace6FaceRecModel implements FaceRecModel{
String[] faceRecognizerModelPath = {config.getModelPath() + File.separator + "face_recognizer.csta"};
String[] faceLandmarkerModelPath = {config.getModelPath() + File.separator + "face_landmarker_pts5.csta"};
SeetaDevice device = SeetaDevice.SEETA_DEVICE_AUTO;
int gpuId = 0;
int gpuId = config.getGpuId();
if(Objects.nonNull(config.getDevice())){
device = config.getDevice() == DeviceEnum.CPU ? SeetaDevice.SEETA_DEVICE_CPU : SeetaDevice.SEETA_DEVICE_GPU;
Integer gpuIdValue = config.getCustomParam("gpuId", Integer.class);
if(Objects.nonNull(gpuIdValue) && device == SeetaDevice.SEETA_DEVICE_GPU){
gpuId = gpuIdValue;
}
}
try {
SeetaModelSetting faceDetectorPoolSetting = new SeetaModelSetting(gpuId, faceDetectorModelPath, device);
@@ -115,6 +112,16 @@ public class SeetaFace6FaceRecModel implements FaceRecModel{
this.faceLandmarkerPool = new FaceLandmarkerPool(faceLandmarkerPoolConfSetting);
this.faceDatabasePool = new FaceDatabasePool(faceDatabasePoolConfSetting);
int predictorPoolSize = config.getPredictorPoolSize();
if(config.getPredictorPoolSize() <= 0){
predictorPoolSize = Runtime.getRuntime().availableProcessors(); // 默认等于CPU核心数
}
faceDetectorPool.setMaxTotal(predictorPoolSize);
faceRecognizerPool.setMaxTotal(predictorPoolSize);
faceLandmarkerPool.setMaxTotal(predictorPoolSize);
faceDatabasePool.setMaxTotal(predictorPoolSize);
log.debug("模型推理器线程池最大数量: " + predictorPoolSize);
//初始化人脸库
if(config.getVectorDBConfig() != null && config.getVectorDBConfig().getType() != null){
@@ -739,6 +746,36 @@ public class SeetaFace6FaceRecModel implements FaceRecModel{
}
}
/**
* 特征提取
* @param image
* @return
*/
public float[] featureExtraction(BufferedImage image){
FaceRecognizer faceRecognizer = null;
try {
faceRecognizer = faceRecognizerPool.borrowObject();
SeetaImageData imageData = new SeetaImageData(image.getWidth(), image.getHeight(), 3);
imageData.data = ImageUtils.getMatrixBGR(image);
//提取特征
float[] features = new float[faceRecognizer.GetExtractFeatureSize()];
faceRecognizer.ExtractCroppedFace(imageData, features);
return features;
} catch (FaceException e) {
throw e;
} catch (Exception e) {
throw new FaceException("目标检测错误", e);
}finally {
if (faceRecognizer != null) {
try {
faceRecognizerPool.returnObject(faceRecognizer); //归还
} catch (Exception e) {
log.warn("归还Predictor失败", e);
}
}
}
}
@Override
public R<float[]> extractTopFaceFeature(String imagePath) {
if(!FileUtils.isFileExists(imagePath)){
@@ -878,4 +915,19 @@ public class SeetaFace6FaceRecModel implements FaceRecModel{
}
public FaceDetectorPool getFaceDetectorPool() {
return faceDetectorPool;
}
public FaceRecognizerPool getFaceRecognizerPool() {
return faceRecognizerPool;
}
public FaceLandmarkerPool getFaceLandmarkerPool() {
return faceLandmarkerPool;
}
public FaceDatabasePool getFaceDatabasePool() {
return faceDatabasePool;
}
}

View File

@@ -27,7 +27,7 @@ public class FaceRecCriteriaFactory {
public static Criteria<Image, float[]> createCriteria(FaceRecConfig config) {
Device device = null;
if(!Objects.isNull(config.getDevice())){
device = config.getDevice() == DeviceEnum.CPU ? Device.cpu() : Device.gpu();
device = config.getDevice() == DeviceEnum.CPU ? Device.cpu() : Device.gpu(config.getGpuId());
}
Criteria<Image, float[]> criteria = null;
if(config.getModelEnum() == FaceRecModelEnum.FACENET_MODEL){
@@ -58,6 +58,7 @@ public class FaceRecCriteriaFactory {
.optTranslator(new FaceFeatureTranslator())
.optEngine("PyTorch") // Use PyTorch engine
.optProgress(new ProgressBar())
.optDevice(device)
.build();
}else if (config.getModelEnum() == FaceRecModelEnum.INSIGHT_FACE_IRSE50_MODEL){
if(StringUtils.isBlank(config.getModelPath())){
@@ -73,6 +74,7 @@ public class FaceRecCriteriaFactory {
// .optArgument("resize", "112,112")
.optTranslator(new FaceFeatureTranslator())
.optEngine("PyTorch") // Use PyTorch engine
.optDevice(device)
.optProgress(new ProgressBar())
.build();
}else if (config.getModelEnum() == FaceRecModelEnum.ELASTIC_FACE_MODEL){
@@ -89,6 +91,7 @@ public class FaceRecCriteriaFactory {
// .optArgument("resize", "112,112")
.optTranslator(new FaceFeatureTranslator())
.optEngine("PyTorch") // Use PyTorch engine
.optDevice(device)
.optProgress(new ProgressBar())
.build();
}

View File

@@ -31,7 +31,7 @@ public final class FaceFeatureTranslator implements Translator<Image, float[]> {
NDArray array = input.toNDArray(ctx.getNDManager(), Image.Flag.COLOR);
Pipeline pipeline = new Pipeline();
if(input.getWidth() != 112 || input.getHeight() != 112){
pipeline.add(new Resize(112));
pipeline.add(new Resize(112,112));
}
pipeline
.add(new ToTensor())

View File

@@ -2,6 +2,7 @@ package cn.smartjavaai.face.model.liveness;
import ai.djl.Device;
import ai.djl.MalformedModelException;
import ai.djl.engine.Engine;
import ai.djl.inference.Predictor;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
@@ -35,6 +36,7 @@ import org.apache.commons.pool2.impl.GenericObjectPool;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameUtils;
import org.opencv.core.Mat;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
@@ -54,7 +56,7 @@ import java.util.*;
@Slf4j
public class CommonLivenessModel implements LivenessDetModel{
protected ObjectPool<Predictor<Image, Float>> predictorPool;
protected GenericObjectPool<Predictor<Image, Float>> predictorPool;
protected LivenessConfig config;
@@ -78,6 +80,15 @@ public class CommonLivenessModel implements LivenessDetModel{
} catch (IOException | ModelNotFoundException | MalformedModelException e) {
throw new FaceException("阿里通义实验室活体检测模型加载失败", e);
}
int predictorPoolSize = config.getPredictorPoolSize();
if(config.getPredictorPoolSize() <= 0){
predictorPoolSize = Runtime.getRuntime().availableProcessors(); // 默认等于CPU核心数
}
predictorPool.setMaxTotal(predictorPoolSize);
log.debug("当前设备: " + model.getNDManager().getDevice());
log.debug("当前引擎: " + Engine.getInstance().getEngineName());
log.debug("模型推理器线程池最大数量: " + predictorPoolSize);
}
@@ -87,6 +98,7 @@ public class CommonLivenessModel implements LivenessDetModel{
throw new FaceException("图像无效");
}
Predictor<Image, Float> predictor = null;
Image djlImage = null;
try {
predictor = predictorPool.borrowObject();
//预处理图片
@@ -101,7 +113,7 @@ public class CommonLivenessModel implements LivenessDetModel{
.setCenterCropSize(112)
.process();
}
Image djlImage = ImageFactory.getInstance().fromImage(OpenCVUtils.image2Mat(processedImage));
djlImage = ImageFactory.getInstance().fromImage(OpenCVUtils.image2Mat(processedImage));
Float result = predictor.predict(djlImage);
if(result >= config.getRealityThreshold()){
return R.ok(new LivenessResult(LivenessStatus.LIVE, result));
@@ -124,6 +136,10 @@ public class CommonLivenessModel implements LivenessDetModel{
}
}
}
if (djlImage != null){
((Mat)djlImage.getWrappedImage()).release();
}
}
}
@@ -403,6 +419,12 @@ public class CommonLivenessModel implements LivenessDetModel{
return R.fail(R.Status.Unknown);
}
@Override
public GenericObjectPool<Predictor<Image, Float>> getPool() {
return predictorPool;
}
@Override
public void close() throws Exception {
try {

View File

@@ -1,11 +1,14 @@
package cn.smartjavaai.face.model.liveness;
import ai.djl.inference.Predictor;
import ai.djl.modality.cv.Image;
import cn.smartjavaai.common.entity.DetectionRectangle;
import cn.smartjavaai.common.entity.DetectionResponse;
import cn.smartjavaai.common.entity.Point;
import cn.smartjavaai.common.entity.R;
import cn.smartjavaai.common.entity.face.LivenessResult;
import cn.smartjavaai.face.config.LivenessConfig;
import org.apache.commons.pool2.impl.GenericObjectPool;
import java.awt.image.BufferedImage;
import java.io.InputStream;
@@ -292,6 +295,9 @@ public interface LivenessDetModel extends AutoCloseable{
default GenericObjectPool<Predictor<Image, Float>> getPool() {
throw new UnsupportedOperationException("默认不支持该功能");
}

View File

@@ -2,6 +2,7 @@ package cn.smartjavaai.face.model.liveness;
import ai.djl.Device;
import ai.djl.MalformedModelException;
import ai.djl.engine.Engine;
import ai.djl.inference.Predictor;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
@@ -33,6 +34,7 @@ import org.apache.commons.pool2.impl.GenericObjectPool;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameUtils;
import org.opencv.core.Mat;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
@@ -58,9 +60,9 @@ public class MiniVisionLivenessModel extends CommonLivenessModel{
*/
private static final String SE_MODEL_PATH_KEY = "seModelPath";
private ObjectPool<Predictor<Image, float[]>> predictorPool;
private GenericObjectPool<Predictor<Image, float[]>> predictorPool;
private ObjectPool<Predictor<Image, float[]>> sePredictorPool;
private GenericObjectPool<Predictor<Image, float[]>> sePredictorPool;
/**
@@ -87,7 +89,7 @@ public class MiniVisionLivenessModel extends CommonLivenessModel{
this.config.setRealityThreshold(realityThreshold);
Device device = null;
if(!Objects.isNull(config.getDevice())){
device = config.getDevice() == DeviceEnum.CPU ? Device.cpu() : Device.gpu();
device = config.getDevice() == DeviceEnum.CPU ? Device.cpu() : Device.gpu(config.getGpuId());
}
if(StringUtils.isNotBlank(config.getModelPath()) && StringUtils.isBlank(seModelPath)){
//2.7_80x80_MiniFASNetV2
@@ -109,6 +111,7 @@ public class MiniVisionLivenessModel extends CommonLivenessModel{
.optModelPath(Paths.get(config.getModelPath()))
.optTranslator(new MiniVisionTranslator())
.optProgress(new ProgressBar())
.optDevice(device)
.build();
try {
model = criteria.loadModel();
@@ -128,6 +131,7 @@ public class MiniVisionLivenessModel extends CommonLivenessModel{
.optModelPath(Paths.get(seModelPath))
.optTranslator(new MiniVisionTranslator())
.optProgress(new ProgressBar())
.optDevice(device)
.build();
try {
seModel = seCriteria.loadModel();
@@ -136,6 +140,16 @@ public class MiniVisionLivenessModel extends CommonLivenessModel{
throw new FaceException("MiniFASNetV1SE模型加载失败", e);
}
}
int predictorPoolSize = config.getPredictorPoolSize();
if(config.getPredictorPoolSize() <= 0){
predictorPoolSize = Runtime.getRuntime().availableProcessors(); // 默认等于CPU核心数
}
predictorPool.setMaxTotal(predictorPoolSize);
sePredictorPool.setMaxTotal(predictorPoolSize);
log.debug("当前设备: " + model.getNDManager().getDevice());
log.debug("当前引擎: " + Engine.getInstance().getEngineName());
log.debug("模型推理器线程池最大数量: " + predictorPoolSize);
}
@@ -160,6 +174,8 @@ public class MiniVisionLivenessModel extends CommonLivenessModel{
predictor = predictorPool.borrowObject();
Image djlImage = ImageFactory.getInstance().fromImage(OpenCVUtils.image2Mat(processedImage));
result = predictor.predict(djlImage);
((Mat)djlImage.getWrappedImage()).release();
}
if(Objects.nonNull(sePredictorPool)){
//预处理图片
@@ -172,6 +188,7 @@ public class MiniVisionLivenessModel extends CommonLivenessModel{
Image djlImage = ImageFactory.getInstance().fromImage(OpenCVUtils.image2Mat(processedImage));
sePredictor = sePredictorPool.borrowObject();
seResult = sePredictor.predict(djlImage);
((Mat)djlImage.getWrappedImage()).release();
}
if(Objects.isNull(result) && Objects.isNull(seResult)){
throw new FaceException("活体检测错误");
@@ -221,6 +238,14 @@ public class MiniVisionLivenessModel extends CommonLivenessModel{
}
}
public GenericObjectPool<Predictor<Image, float[]>> getPredictorPool() {
return predictorPool;
}
public GenericObjectPool<Predictor<Image, float[]>> getSePredictorPool() {
return sePredictorPool;
}
@Override
public void close() throws Exception {
try {

View File

@@ -1,5 +1,6 @@
package cn.smartjavaai.face.model.liveness;
import ai.djl.engine.Engine;
import cn.smartjavaai.common.entity.*;
import cn.smartjavaai.common.entity.face.FaceInfo;
import cn.smartjavaai.common.entity.face.LivenessResult;
@@ -56,13 +57,9 @@ public class Seetaface6LivenessModel implements LivenessDetModel{
String[] faceAntiSpoofingModelPath = {config.getModelPath() + File.separator + "fas_first.csta",config.getModelPath() + File.separator + "fas_second.csta"};
String[] faceLandmarkerModelPath = {config.getModelPath() + File.separator + "face_landmarker_pts5.csta"};
SeetaDevice device = SeetaDevice.SEETA_DEVICE_AUTO;
int gpuId = 0;
int gpuId = config.getGpuId();
if(Objects.nonNull(config.getDevice())){
device = config.getDevice() == DeviceEnum.CPU ? SeetaDevice.SEETA_DEVICE_CPU : SeetaDevice.SEETA_DEVICE_GPU;
Integer gpuIdValue = config.getCustomParam("gpuId", Integer.class);
if(Objects.nonNull(gpuIdValue) && device == SeetaDevice.SEETA_DEVICE_GPU){
gpuId = gpuIdValue;
}
}
try {
@@ -79,6 +76,16 @@ public class Seetaface6LivenessModel implements LivenessDetModel{
this.faceAntiSpoofingPool = new FaceAntiSpoofingPool(faceAntiSpoofingPoolConfSetting);
this.faceLandmarkerPool = new FaceLandmarkerPool(faceLandmarkerPoolConfSetting);
int predictorPoolSize = config.getPredictorPoolSize();
if(config.getPredictorPoolSize() <= 0){
predictorPoolSize = Runtime.getRuntime().availableProcessors(); // 默认等于CPU核心数
}
faceDetectorPool.setMaxTotal(predictorPoolSize);
faceAntiSpoofingPool.setMaxTotal(predictorPoolSize);
faceLandmarkerPool.setMaxTotal(predictorPoolSize);
log.debug("模型推理器线程池最大数量: " + predictorPoolSize);
//初始化模型参数
initConfig();
} catch (FileNotFoundException e) {
@@ -550,6 +557,18 @@ public class Seetaface6LivenessModel implements LivenessDetModel{
return R.fail(1000, "有效帧数量不足,无法完成活体检测");
}
public FaceDetectorPool getFaceDetectorPool() {
return faceDetectorPool;
}
public FaceAntiSpoofingPool getFaceAntiSpoofingPool() {
return faceAntiSpoofingPool;
}
public FaceLandmarkerPool getFaceLandmarkerPool() {
return faceLandmarkerPool;
}
@Override
public void close() throws Exception {
try {

View File

@@ -31,7 +31,7 @@ public class LivenessCriteriaFactory {
public static Criteria<Image, Float> createCriteria(LivenessConfig config) {
Device device = null;
if(!Objects.isNull(config.getDevice())){
device = config.getDevice() == DeviceEnum.CPU ? Device.cpu() : Device.gpu();
device = config.getDevice() == DeviceEnum.CPU ? Device.cpu() : Device.gpu(config.getGpuId());
}
Criteria<Image, Float> criteria = null;
if(config.getModelEnum() == LivenessModelEnum.IIC_FL_MODEL){

View File

@@ -1,5 +1,6 @@
package cn.smartjavaai.face.model.quality;
import ai.djl.engine.Engine;
import cn.smartjavaai.common.entity.*;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.common.utils.FileUtils;
@@ -74,6 +75,8 @@ public class Seetaface6QualityModel implements FaceQualityModel {
*/
private QualityOfResolutionPool qualityOfResolutionPool;
int predictorPoolSize = 0;
@Override
public void loadModel(QualityConfig config) {
@@ -84,6 +87,11 @@ public class Seetaface6QualityModel implements FaceQualityModel {
//加载依赖库
NativeLoader.loadNativeLibraries(device);
this.config = config;
int predictorPoolSize = config.getPredictorPoolSize();
if(config.getPredictorPoolSize() <= 0){
predictorPoolSize = Runtime.getRuntime().availableProcessors(); // 默认等于CPU核心数
}
log.debug("模型推理器线程池最大数量: " + predictorPoolSize);
log.debug("Loading seetaFace6 library successfully.");
}
@@ -104,6 +112,7 @@ public class Seetaface6QualityModel implements FaceQualityModel {
try {
if(Objects.isNull(this.qualityOfBrightnessPool)){
this.qualityOfBrightnessPool = new QualityOfBrightnessPool(new SeetaConfSetting());
qualityOfBrightnessPool.setMaxTotal(predictorPoolSize);
}
qualityOfBrightness = qualityOfBrightnessPool.borrowObject();
SeetaImageData imageData = new SeetaImageData(image.getWidth(), image.getHeight(), 3);
@@ -170,6 +179,7 @@ public class Seetaface6QualityModel implements FaceQualityModel {
try {
if(Objects.isNull(this.qualityOfClarityPool)){
this.qualityOfClarityPool = new QualityOfClarityPool(new SeetaConfSetting());
qualityOfClarityPool.setMaxTotal(predictorPoolSize);
}
qualityOfClarity = qualityOfClarityPool.borrowObject();
SeetaImageData imageData = new SeetaImageData(image.getWidth(), image.getHeight(), 3);
@@ -236,6 +246,7 @@ public class Seetaface6QualityModel implements FaceQualityModel {
try {
if(Objects.isNull(this.qualityOfIntegrityPool)){
this.qualityOfIntegrityPool = new QualityOfIntegrityPool(new SeetaConfSetting());
qualityOfIntegrityPool.setMaxTotal(predictorPoolSize);
}
qualityOfIntegrity = qualityOfIntegrityPool.borrowObject();
SeetaImageData imageData = new SeetaImageData(image.getWidth(), image.getHeight(), 3);
@@ -302,6 +313,7 @@ public class Seetaface6QualityModel implements FaceQualityModel {
try {
if(Objects.isNull(this.qualityOfPosePool)){
this.qualityOfPosePool = new QualityOfPosePool(new SeetaConfSetting());
qualityOfPosePool.setMaxTotal(predictorPoolSize);
}
qualityOfPose = qualityOfPosePool.borrowObject();
SeetaImageData imageData = new SeetaImageData(image.getWidth(), image.getHeight(), 3);
@@ -368,6 +380,7 @@ public class Seetaface6QualityModel implements FaceQualityModel {
try {
if(Objects.isNull(this.qualityOfResolutionPool)){
this.qualityOfResolutionPool = new QualityOfResolutionPool(new SeetaConfSetting());
qualityOfResolutionPool.setMaxTotal(predictorPoolSize);
}
qualityOfResolution = qualityOfResolutionPool.borrowObject();
SeetaImageData imageData = new SeetaImageData(image.getWidth(), image.getHeight(), 3);
@@ -438,6 +451,7 @@ public class Seetaface6QualityModel implements FaceQualityModel {
}
SeetaConfSetting setting = getClarityMLSetting();
this.qualityOfLBNPool = new QualityOfLBNPool(setting);
qualityOfLBNPool.setMaxTotal(predictorPoolSize);
}
qualityOfLBN = qualityOfLBNPool.borrowObject();
SeetaImageData imageData = new SeetaImageData(image.getWidth(), image.getHeight(), 3);
@@ -509,6 +523,7 @@ public class Seetaface6QualityModel implements FaceQualityModel {
}
SeetaConfSetting setting = getPoseMLSetting();
this.qualityOfPoseExPool = new QualityOfPoseExPool(setting);
qualityOfPoseExPool.setMaxTotal(predictorPoolSize);
}
qualityOfPoseEx = qualityOfPoseExPool.borrowObject();
SeetaImageData imageData = new SeetaImageData(image.getWidth(), image.getHeight(), 3);
@@ -628,18 +643,23 @@ public class Seetaface6QualityModel implements FaceQualityModel {
try {
if(Objects.isNull(this.qualityOfBrightnessPool)){
this.qualityOfBrightnessPool = new QualityOfBrightnessPool(new SeetaConfSetting());
qualityOfBrightnessPool.setMaxTotal(predictorPoolSize);
}
if(Objects.isNull(this.qualityOfClarityPool)){
this.qualityOfClarityPool = new QualityOfClarityPool(new SeetaConfSetting());
qualityOfClarityPool.setMaxTotal(predictorPoolSize);
}
if(Objects.isNull(this.qualityOfIntegrityPool)){
this.qualityOfIntegrityPool = new QualityOfIntegrityPool(new SeetaConfSetting());
qualityOfIntegrityPool.setMaxTotal(predictorPoolSize);
}
if(Objects.isNull(this.qualityOfPosePool)){
this.qualityOfPosePool = new QualityOfPosePool(new SeetaConfSetting());
qualityOfPosePool.setMaxTotal(predictorPoolSize);
}
if(Objects.isNull(this.qualityOfResolutionPool)){
this.qualityOfResolutionPool = new QualityOfResolutionPool(new SeetaConfSetting());
qualityOfResolutionPool.setMaxTotal(predictorPoolSize);
}
FaceQualitySummary summary = new FaceQualitySummary();
qualityOfBrightness = qualityOfBrightnessPool.borrowObject();
@@ -690,6 +710,34 @@ public class Seetaface6QualityModel implements FaceQualityModel {
}
}
public QualityOfBrightnessPool getQualityOfBrightnessPool() {
return qualityOfBrightnessPool;
}
public QualityOfClarityPool getQualityOfClarityPool() {
return qualityOfClarityPool;
}
public QualityOfLBNPool getQualityOfLBNPool() {
return qualityOfLBNPool;
}
public QualityOfIntegrityPool getQualityOfIntegrityPool() {
return qualityOfIntegrityPool;
}
public QualityOfPosePool getQualityOfPosePool() {
return qualityOfPosePool;
}
public QualityOfPoseExPool getQualityOfPoseExPool() {
return qualityOfPoseExPool;
}
public QualityOfResolutionPool getQualityOfResolutionPool() {
return qualityOfResolutionPool;
}
@Override
public void close() throws Exception {
if(Objects.nonNull(qualityOfBrightnessPool)){

View File

@@ -60,15 +60,13 @@ public class DJLImagePreprocessor {
// 处理流程
public Image process() {
Image result = image;
if (enableCrop) {
result = result.getSubImage(cropRect.x, cropRect.y, cropRect.width, cropRect.height);
}
if (enableAffine) {
if(enableAffine){
result = warpAffine(keyPoints, affineTargetWidth, affineTargetHeight);
}else {
if(enableCrop){
result = result.getSubImage(cropRect.x, cropRect.y, cropRect.width, cropRect.height);
}
}
return result;
}

View File

@@ -62,6 +62,16 @@ public class MilvusConfig extends VectorDBConfig {
*/
private boolean useMemoryCache = true;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 构造函数
*/

View File

@@ -49,10 +49,13 @@ public class MilvusClient implements VectorDBClient {
@Override
public void initialize() {
try {
ConnectParam connectParam = ConnectParam.newBuilder()
ConnectParam.Builder builder = ConnectParam.newBuilder()
.withHost(config.getHost())
.withPort(config.getPort())
.build();
.withPort(config.getPort());
if (StringUtils.isNotBlank(config.getUsername()) && StringUtils.isNotBlank(config.getPassword())) {
builder.withAuthorization(config.getUsername(), config.getPassword());
}
ConnectParam connectParam = builder.build();
serviceClient = new MilvusServiceClient(connectParam);
collectionName = StringUtils.isNotBlank(config.getCollectionName()) ? config.getCollectionName() : VectorDBConstants.Defaults.DEFAULT_COLLECTION_NAME;
createCollection(collectionName, config.getDimension());