mirror of
https://github.com/geekwenjie/SmartJavaAI.git
synced 2026-09-12 20:58:51 +00:00
1、OCR:新增表格识别模型
2、OCR:新增9个通用模型 3、OCR:支持批量检测识别 4、OCR:新增更多参数,使用更加灵活 5、人脸识别:支持ID查询及分页获取人脸信息 6、活体检测:视频检测支持设置最大帧数
This commit is contained in:
@@ -6,11 +6,11 @@
|
||||
<parent>
|
||||
<groupId>cn.smartjavaai</groupId>
|
||||
<artifactId>smartjavaai-parent</artifactId>
|
||||
<version>1.0.19</version>
|
||||
<version>1.0.20</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>smartjavaai-face</artifactId>
|
||||
<version>1.0.19</version>
|
||||
<version>1.0.20</version>
|
||||
<name>smartjavaai-face</name>
|
||||
<description>SmartJavaAI</description>
|
||||
<url>https://github.com/geekwenjie/SmartJavaAI</url>
|
||||
|
||||
@@ -23,31 +23,11 @@ public class FaceRecConfig {
|
||||
*/
|
||||
private FaceRecModelEnum modelEnum;
|
||||
|
||||
/**
|
||||
* 置信度阈值
|
||||
*/
|
||||
private double confidenceThreshold = FaceDetectConstant.DEFAULT_CONFIDENCE_THRESHOLD;
|
||||
|
||||
/**
|
||||
* 相似度阈值 作用:判断是否为同一人脸
|
||||
*/
|
||||
//private double similarityThreshold = 0D;
|
||||
|
||||
/**
|
||||
* 非极大抑制阈值 作用:消除重叠检测框,保留最优结果
|
||||
*/
|
||||
private double nmsThresh = FaceDetectConstant.NMS_THRESHOLD;
|
||||
|
||||
/**
|
||||
* 模型路径
|
||||
*/
|
||||
private String modelPath;
|
||||
|
||||
/**
|
||||
* 人脸库路径
|
||||
*/
|
||||
private String faceDbPath;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
|
||||
@@ -48,6 +48,11 @@ public class LivenessConfig {
|
||||
*/
|
||||
private int frameCount = LivenessConstant.DEFAULT_FRAME_COUNT;
|
||||
|
||||
/**
|
||||
* 视频检测最大帧数
|
||||
*/
|
||||
private int maxVideoDetectFrames = LivenessConstant.DEFAULT_MAX_VIDEO_DETECT_FRAMES;
|
||||
|
||||
/**
|
||||
* 真人阈值
|
||||
*/
|
||||
|
||||
@@ -24,4 +24,9 @@ public class LivenessConstant {
|
||||
* 视频默认检测帧数
|
||||
*/
|
||||
public static final int DEFAULT_FRAME_COUNT = 10;
|
||||
|
||||
/**
|
||||
* 视频默认最大检测帧数
|
||||
*/
|
||||
public static final int DEFAULT_MAX_VIDEO_DETECT_FRAMES = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package cn.smartjavaai.face.dao;
|
||||
|
||||
import cn.smartjavaai.face.entity.FaceData;
|
||||
import cn.smartjavaai.face.sqllite.RowMapper;
|
||||
import cn.smartjavaai.face.sqllite.SqliteHelper;
|
||||
import cn.smartjavaai.face.utils.VectorUtils;
|
||||
@@ -80,7 +79,7 @@ public class FaceDao {
|
||||
*/
|
||||
public FaceVector findById(String id) throws SQLException, ClassNotFoundException {
|
||||
SqliteHelper sqliteHelper = SqliteHelper.getInstance(dbFilePath);
|
||||
String sql = "select \"id\",\"vector\",\"metadata\" from " + FACE_TABLE_NAME + " where \"id\"=" + id;
|
||||
String sql = "select \"id\",\"vector\",\"metadata\" from " + FACE_TABLE_NAME + " where \"id\" = '" + id + "'";
|
||||
List<FaceVector> faceVectors = sqliteHelper.executeQuery(sql, new RowMapper<FaceVector>() {
|
||||
@Override
|
||||
public FaceVector mapRow(ResultSet rs, int id) throws SQLException {
|
||||
@@ -164,8 +163,9 @@ public class FaceDao {
|
||||
* @throws ClassNotFoundException 类未找到异常
|
||||
*/
|
||||
public List<FaceVector> findFace(int pageNo, int pageSize) throws SQLException, ClassNotFoundException {
|
||||
long offset = (pageNo - 1) * pageSize;
|
||||
String sql = "select \"id\",\"vector\",\"metadata\" from " + FACE_TABLE_NAME +
|
||||
" limit " + pageNo * pageSize + "," + pageSize;
|
||||
" limit " + offset + "," + pageSize;
|
||||
SqliteHelper sqliteHelper = SqliteHelper.getInstance(dbFilePath);
|
||||
return sqliteHelper.executeQuery(sql, new RowMapper<FaceVector>() {
|
||||
@Override
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package cn.smartjavaai.face.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 人脸数据
|
||||
* @author dwj
|
||||
*/
|
||||
@Data
|
||||
public class FaceData {
|
||||
|
||||
private String key;
|
||||
private long index;
|
||||
private byte[] imgData;
|
||||
private int width = 256;
|
||||
private int height = 256;
|
||||
private int channel = 3;
|
||||
|
||||
}
|
||||
@@ -24,6 +24,9 @@ public class ExpressionModelFactory {
|
||||
// 使用 volatile 和双重检查锁定来确保线程安全的单例模式
|
||||
private static volatile ExpressionModelFactory instance;
|
||||
|
||||
/**
|
||||
* 模型缓存
|
||||
*/
|
||||
private static final ConcurrentHashMap<ExpressionModelEnum, ExpressionModel> modelMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,8 +9,6 @@ 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.hutool.core.lang.generator.UUIDGenerator;
|
||||
import cn.smartjavaai.common.entity.*;
|
||||
import cn.smartjavaai.common.entity.face.FaceInfo;
|
||||
import cn.smartjavaai.common.entity.face.FaceSearchResult;
|
||||
@@ -28,7 +26,7 @@ import cn.smartjavaai.face.enums.SimilarityType;
|
||||
import cn.smartjavaai.face.exception.FaceException;
|
||||
import cn.smartjavaai.face.factory.FaceDetModelFactory;
|
||||
import cn.smartjavaai.face.model.facedect.FaceDetModel;
|
||||
import cn.smartjavaai.face.model.facerec.criterial.FaceRecCriteriaFactory;
|
||||
import cn.smartjavaai.face.model.facerec.criteria.FaceRecCriteriaFactory;
|
||||
import cn.smartjavaai.face.preprocess.DJLImagePreprocessor;
|
||||
import cn.smartjavaai.face.utils.*;
|
||||
import cn.smartjavaai.face.vector.config.MilvusConfig;
|
||||
@@ -646,6 +644,22 @@ public class CommonFaceRecModel implements FaceRecModel{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<FaceVector> getFaceInfoById(String id) {
|
||||
if(vectorDBClient == null){
|
||||
return R.fail(1000, "向量数据库未初始化成功");
|
||||
}
|
||||
return R.ok(vectorDBClient.getFaceInfoById(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<List<FaceVector>> listFaces(long pageNum, long pageSize) {
|
||||
if(vectorDBClient == null){
|
||||
return R.fail(1000, "向量数据库未初始化成功");
|
||||
}
|
||||
return R.ok(vectorDBClient.listFaces(pageNum, pageSize));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFaceFeatures() {
|
||||
if(Objects.isNull(vectorDBClient)){
|
||||
|
||||
@@ -6,6 +6,7 @@ import cn.smartjavaai.face.config.FaceRecConfig;
|
||||
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 java.awt.image.BufferedImage;
|
||||
import java.io.InputStream;
|
||||
@@ -245,8 +246,26 @@ public interface FaceRecModel extends AutoCloseable{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 使用人脸ID获取人脸信息
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
default R<FaceVector> getFaceInfoById(String id){
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取人脸列表
|
||||
* @param pageNum
|
||||
* @param pageSize
|
||||
* @return
|
||||
*/
|
||||
default R<List<FaceVector>> listFaces(long pageNum, long pageSize){
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除已注册人脸
|
||||
|
||||
@@ -486,13 +486,13 @@ public class SeetaFace6FaceRecModel implements FaceRecModel{
|
||||
* 检查是否存在人脸库
|
||||
* @return
|
||||
*/
|
||||
private boolean checkFaceDb(){
|
||||
if(Objects.nonNull(config) && StringUtils.isNotBlank(config.getFaceDbPath())){
|
||||
File file = new File(config.getFaceDbPath());
|
||||
return file.exists() && file.isFile();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// private boolean checkFaceDb(){
|
||||
// if(Objects.nonNull(config) && StringUtils.isNotBlank(config.getFaceDbPath())){
|
||||
// File file = new File(config.getFaceDbPath());
|
||||
// return file.exists() && file.isFile();
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
private FaceResult searchFaceDb(long index,float similar) {
|
||||
if(index >= 0){
|
||||
@@ -837,6 +837,22 @@ public class SeetaFace6FaceRecModel implements FaceRecModel{
|
||||
FaceRecModel.super.upsertFace(faceRegisterInfo, imageData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<FaceVector> getFaceInfoById(String id) {
|
||||
if(vectorDBClient == null){
|
||||
return R.fail(1000, "向量数据库未初始化成功");
|
||||
}
|
||||
return R.ok(vectorDBClient.getFaceInfoById(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<List<FaceVector>> listFaces(long pageNum, long pageSize) {
|
||||
if(vectorDBClient == null){
|
||||
return R.fail(1000, "向量数据库未初始化成功");
|
||||
}
|
||||
return R.ok(vectorDBClient.listFaces(pageNum, pageSize));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
if(Objects.nonNull(faceDetectorPool)){
|
||||
|
||||
@@ -1,28 +1,15 @@
|
||||
package cn.smartjavaai.face.model.facerec.criterial;
|
||||
package cn.smartjavaai.face.model.facerec.criteria;
|
||||
|
||||
import ai.djl.Device;
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.modality.cv.transform.Normalize;
|
||||
import ai.djl.modality.cv.transform.Resize;
|
||||
import ai.djl.modality.cv.transform.ToTensor;
|
||||
import ai.djl.modality.cv.translator.ImageFeatureExtractor;
|
||||
import ai.djl.modality.cv.translator.ImageFeatureExtractorFactory;
|
||||
import ai.djl.repository.zoo.Criteria;
|
||||
import ai.djl.training.util.ProgressBar;
|
||||
import ai.djl.translate.Translator;
|
||||
import cn.smartjavaai.common.enums.DeviceEnum;
|
||||
import cn.smartjavaai.face.config.FaceDetConfig;
|
||||
import cn.smartjavaai.face.config.FaceRecConfig;
|
||||
import cn.smartjavaai.face.constant.FaceDetectConstant;
|
||||
import cn.smartjavaai.face.constant.FaceNetConstant;
|
||||
import cn.smartjavaai.face.constant.RetinaFaceConstant;
|
||||
import cn.smartjavaai.face.constant.UltraLightFastGenericFaceConstant;
|
||||
import cn.smartjavaai.face.enums.FaceDetModelEnum;
|
||||
import cn.smartjavaai.face.enums.FaceRecModelEnum;
|
||||
import cn.smartjavaai.face.model.facerec.translator.FaceFeatureTranslator;
|
||||
import cn.smartjavaai.face.model.facerec.translator.FaceNetRecTranslator;
|
||||
import cn.smartjavaai.face.translator.FaceDetectionTranslator;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
@@ -354,6 +354,9 @@ public class CommonLivenessModel implements LivenessDetModel{
|
||||
}
|
||||
// 逐帧处理视频
|
||||
for (int frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
|
||||
if(frameIndex >= config.getMaxVideoDetectFrames()){
|
||||
return R.fail(10002, "超出最大检测帧数:" + config.getMaxVideoDetectFrames());
|
||||
}
|
||||
// 获取当前帧
|
||||
Frame frame = grabber.grabImage();
|
||||
if (frame != null) {
|
||||
|
||||
@@ -515,6 +515,9 @@ public class Seetaface6LivenessModel implements LivenessDetModel{
|
||||
}
|
||||
// 逐帧处理视频
|
||||
for (int frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
|
||||
if(frameIndex >= config.getMaxVideoDetectFrames()){
|
||||
return R.fail(10002, "超出最大检测帧数:" + config.getMaxVideoDetectFrames());
|
||||
}
|
||||
// 获取当前帧
|
||||
Frame frame = grabber.grabImage();
|
||||
if (frame != null) {
|
||||
|
||||
@@ -14,8 +14,11 @@ import io.milvus.param.*;
|
||||
import io.milvus.param.collection.*;
|
||||
import io.milvus.param.dml.*;
|
||||
import io.milvus.param.index.CreateIndexParam;
|
||||
import io.milvus.response.DescCollResponseWrapper;
|
||||
import io.milvus.response.QueryResultsWrapper;
|
||||
import io.milvus.response.SearchResultsWrapper;
|
||||
import io.milvus.v2.service.collection.request.DescribeCollectionReq;
|
||||
import io.milvus.v2.service.collection.response.DescribeCollectionResp;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -53,6 +56,14 @@ public class MilvusClient implements VectorDBClient {
|
||||
serviceClient = new MilvusServiceClient(connectParam);
|
||||
collectionName = StringUtils.isNotBlank(config.getCollectionName()) ? config.getCollectionName() : VectorDBConstants.Defaults.DEFAULT_COLLECTION_NAME;
|
||||
createCollection(collectionName, config.getDimension());
|
||||
|
||||
boolean isAutoID = isAutoID(collectionName);
|
||||
if(isAutoID && config.getIdStrategy() != IdStrategy.AUTO){
|
||||
throw new VectorDBException("ID策略与当前Collection不匹配");
|
||||
}
|
||||
if(!isAutoID && config.getIdStrategy() == IdStrategy.AUTO){
|
||||
throw new VectorDBException("ID策略与当前Collection不匹配");
|
||||
}
|
||||
if(config.isUseMemoryCache()){
|
||||
// 加载集合到内存
|
||||
loadFaceFeatures();
|
||||
@@ -152,6 +163,21 @@ public class MilvusClient implements VectorDBClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为自增长ID
|
||||
* @param collectionName
|
||||
* @return
|
||||
*/
|
||||
private boolean isAutoID(String collectionName) {
|
||||
R<DescribeCollectionResponse> response = serviceClient.describeCollection(
|
||||
DescribeCollectionParam.newBuilder()
|
||||
.withCollectionName(collectionName)
|
||||
.build()
|
||||
);
|
||||
DescCollResponseWrapper wrapper = new DescCollResponseWrapper(response.getData());
|
||||
return wrapper.getPrimaryField().isAutoID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropCollection(String collectionName) {
|
||||
try {
|
||||
@@ -204,6 +230,7 @@ public class MilvusClient implements VectorDBClient {
|
||||
if(faceVector.getVector() == null || faceVector.getVector().length == 0){
|
||||
throw new VectorDBException("插入数据失败:vector不能为空");
|
||||
}
|
||||
|
||||
//自定义ID
|
||||
if(config.getIdStrategy() == IdStrategy.CUSTOM){
|
||||
if(StringUtils.isBlank(faceVector.getId())){
|
||||
@@ -525,40 +552,22 @@ public class MilvusClient implements VectorDBClient {
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseCollection(String collectionName) {
|
||||
if (!isInit){
|
||||
throw new VectorDBException("Milvus未初始化完毕");
|
||||
}
|
||||
R<RpcStatus> response = serviceClient.releaseCollection(ReleaseCollectionParam.newBuilder()
|
||||
.withCollectionName(collectionName)
|
||||
.build());
|
||||
|
||||
if (response.getStatus() != R.Status.Success.getCode()) {
|
||||
throw new VectorDBException("Milvus releaseCollection失败,msg: " + response.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FaceSearchResult getById(String id) {
|
||||
public FaceVector getFaceInfoById(String id) {
|
||||
try {
|
||||
if (!isInit){
|
||||
if (!isInit) {
|
||||
throw new VectorDBException("Milvus未初始化完毕");
|
||||
}
|
||||
// 构造搜索参数
|
||||
SearchParam searchParam = SearchParam.newBuilder()
|
||||
.withCollectionName(collectionName)
|
||||
.withExpr(VectorDBConstants.FieldNames.ID_FIELD + " == " + id)
|
||||
.withOutFields(Arrays.asList(VectorDBConstants.FieldNames.ID_FIELD, VectorDBConstants.FieldNames.METADATA_FIELD))
|
||||
.build();
|
||||
|
||||
|
||||
String expr = VectorDBConstants.FieldNames.ID_FIELD + " == '" + id + "'";
|
||||
if(config.getIdStrategy() == IdStrategy.AUTO){
|
||||
expr = VectorDBConstants.FieldNames.ID_FIELD + " == " + id;
|
||||
}
|
||||
// 5. 执行查询
|
||||
R<QueryResults> response = serviceClient.query(
|
||||
QueryParam.newBuilder()
|
||||
.withCollectionName(collectionName)
|
||||
.withExpr(VectorDBConstants.FieldNames.ID_FIELD + " == " + id)
|
||||
.withOutFields(Arrays.asList(VectorDBConstants.FieldNames.ID_FIELD, VectorDBConstants.FieldNames.METADATA_FIELD))
|
||||
.withExpr(expr)
|
||||
.withOutFields(Arrays.asList(VectorDBConstants.FieldNames.ID_FIELD, VectorDBConstants.FieldNames.VECTOR_FIELD, VectorDBConstants.FieldNames.METADATA_FIELD))
|
||||
.build()
|
||||
);
|
||||
|
||||
@@ -574,12 +583,91 @@ public class MilvusClient implements VectorDBClient {
|
||||
}
|
||||
// 提取第一条记录
|
||||
QueryResultsWrapper.RowRecord row = records.get(0);
|
||||
return new FaceSearchResult(id, 1,(String)row.get(VectorDBConstants.FieldNames.METADATA_FIELD));
|
||||
Object vectorObj = row.get(VectorDBConstants.FieldNames.VECTOR_FIELD);
|
||||
float[] vector = null;
|
||||
if (vectorObj instanceof List<?>) {
|
||||
// Milvus SDK通常返回List<Float>,转成float[]
|
||||
List<Float> vectorList = (List<Float>) vectorObj;
|
||||
vector = new float[vectorList.size()];
|
||||
for (int i = 0; i < vectorList.size(); i++) {
|
||||
vector[i] = vectorList.get(i);
|
||||
}
|
||||
}
|
||||
return new FaceVector(id, vector, (String) row.get(VectorDBConstants.FieldNames.METADATA_FIELD));
|
||||
} catch (Exception e) {
|
||||
throw new VectorDBException("搜索 Milvus 向量失败", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FaceVector> listFaces(long pageNum, long pageSize) {
|
||||
try {
|
||||
if (!isInit) {
|
||||
throw new VectorDBException("Milvus未初始化完毕");
|
||||
}
|
||||
if (pageNum < 1 || pageSize < 1) {
|
||||
throw new IllegalArgumentException("pageNum和pageSize必须大于0");
|
||||
}
|
||||
long offset = (pageNum - 1) * pageSize;
|
||||
// 构造查询参数,使用offset和limit实现分页
|
||||
QueryParam queryParam = QueryParam.newBuilder()
|
||||
.withCollectionName(collectionName)
|
||||
.withOutFields(Arrays.asList(
|
||||
VectorDBConstants.FieldNames.ID_FIELD,
|
||||
VectorDBConstants.FieldNames.VECTOR_FIELD,
|
||||
VectorDBConstants.FieldNames.METADATA_FIELD))
|
||||
.withOffset(offset)
|
||||
.withLimit(pageSize)
|
||||
.build();
|
||||
|
||||
R<QueryResults> response = serviceClient.query(queryParam);
|
||||
|
||||
if (response.getStatus() != R.Status.Success.getCode()) {
|
||||
throw new VectorDBException("分页查询失败: " + response.getMessage());
|
||||
}
|
||||
|
||||
QueryResultsWrapper wrapper = new QueryResultsWrapper(response.getData());
|
||||
List<QueryResultsWrapper.RowRecord> records = wrapper.getRowRecords();
|
||||
if (records.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<FaceVector> result = new ArrayList<>();
|
||||
for (QueryResultsWrapper.RowRecord row : records) {
|
||||
String id = (String) row.get(VectorDBConstants.FieldNames.ID_FIELD);
|
||||
Object vectorObj = row.get(VectorDBConstants.FieldNames.VECTOR_FIELD);
|
||||
float[] vector = null;
|
||||
if (vectorObj instanceof List<?>) {
|
||||
List<Float> vectorList = (List<Float>) vectorObj;
|
||||
vector = new float[vectorList.size()];
|
||||
for (int i = 0; i < vectorList.size(); i++) {
|
||||
vector[i] = vectorList.get(i);
|
||||
}
|
||||
}
|
||||
String metadata = (String) row.get(VectorDBConstants.FieldNames.METADATA_FIELD);
|
||||
result.add(new FaceVector(id, vector, metadata));
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseCollection(String collectionName) {
|
||||
if (!isInit){
|
||||
throw new VectorDBException("Milvus未初始化完毕");
|
||||
}
|
||||
R<RpcStatus> response = serviceClient.releaseCollection(ReleaseCollectionParam.newBuilder()
|
||||
.withCollectionName(collectionName)
|
||||
.build());
|
||||
|
||||
if (response.getStatus() != R.Status.Success.getCode()) {
|
||||
throw new VectorDBException("Milvus releaseCollection失败,msg: " + response.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void loadFaceFeatures() {
|
||||
// 加载集合到内存
|
||||
|
||||
@@ -196,6 +196,42 @@ public class SQLiteClient implements VectorDBClient {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaceVector getFaceInfoById(String id) {
|
||||
if (!isInit) {
|
||||
throw new VectorDBException("人脸库未加载完毕");
|
||||
}
|
||||
// 先从内存缓存中获取
|
||||
FaceVector faceVector = memoryIndex.get(id);
|
||||
if (faceVector == null) {
|
||||
// 如果内存中没有,则从数据库查询
|
||||
try {
|
||||
faceVector = faceDao.findById(id);
|
||||
} catch (SQLException | ClassNotFoundException e) {
|
||||
throw new VectorDBException("SQLite查询异常", e);
|
||||
}
|
||||
}
|
||||
return faceVector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FaceVector> listFaces(long pageNum, long pageSize) {
|
||||
if (!isInit) {
|
||||
throw new VectorDBException("人脸库未加载完毕");
|
||||
}
|
||||
|
||||
if (pageNum < 1 || pageSize < 1) {
|
||||
throw new IllegalArgumentException("pageNum和pageSize必须大于0");
|
||||
}
|
||||
|
||||
// 从数据库中查询指定分页的数据
|
||||
try {
|
||||
return faceDao.findFace((int)pageNum, (int)pageSize);
|
||||
} catch (Exception e) {
|
||||
throw new VectorDBException("分页查询失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ============= 私有辅助方法 =============
|
||||
|
||||
private void loadAllFeaturesToMemory() {
|
||||
@@ -234,19 +270,6 @@ public class SQLiteClient implements VectorDBClient {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaceSearchResult getById(String id) {
|
||||
try {
|
||||
FaceVector faceVector = faceDao.findById(id);
|
||||
if(faceVector != null){
|
||||
return new FaceSearchResult(faceVector.getId(), 1.0f, faceVector.getMetadata());
|
||||
}
|
||||
return null;
|
||||
} catch (SQLException | RuntimeException | ClassNotFoundException e ) {
|
||||
throw new VectorDBException("SQLite查询异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFaceFeatures() {
|
||||
// 加载所有特征到内存
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.smartjavaai.face.vector.core;
|
||||
|
||||
import cn.smartjavaai.common.entity.R;
|
||||
import cn.smartjavaai.face.entity.FaceSearchParams;
|
||||
import cn.smartjavaai.face.vector.entity.FaceVector;
|
||||
import cn.smartjavaai.common.entity.face.FaceSearchResult;
|
||||
@@ -94,12 +95,21 @@ public interface VectorDBClient extends AutoCloseable {
|
||||
@Override
|
||||
void close();
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定ID的向量
|
||||
* 使用人脸ID获取人脸信息
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
FaceSearchResult getById(String id);
|
||||
FaceVector getFaceInfoById(String id);
|
||||
|
||||
|
||||
/**
|
||||
* 获取人脸列表
|
||||
* @param pageNum
|
||||
* @param pageSize
|
||||
* @return
|
||||
*/
|
||||
List<FaceVector> listFaces(long pageNum, long pageSize);
|
||||
|
||||
/**
|
||||
* 加载人脸特征到内存
|
||||
|
||||
Reference in New Issue
Block a user