SpringBoot 基于向量搜索引擎及虹软人脸识别SDK的大规模人脸搜索
SpringBoot 基于向量搜索引擎及虹软人脸识别SDK的大规模向量数据搜索
文章目录
- SpringBoot 基于向量搜索引擎及虹软人脸识别SDK的大规模向量数据搜索
- 在线环境demo
- 在线环境说明
- 前言
- 系统架构
- 功能设计
- Milvues
- 人脸上传(单张)
- 人脸上传(批量)
- 人脸搜索
- 技术架构
- 前端框架
- 后端框架
- 数据库
- 中间件
- 前后端交互
- 安装部署
- 前端
- 后端配置
- 服务
- 数据库
- 人脸数据
- 核心方法
- FaceEngineConfig 类
- FaceEnginePoolFactory 引擎对象工厂类
- faceUtils 人脸识别工具类
- milvusOperateUtils Milvues工具类
- 相关文档
- 虹软
- Milvus
在线环境demo
为了方便大家测试效果,开放了一个在线环境供大家测试并降低了识别门槛和难度,使得照片也可以通过筛选,大家使用前无比观看视频,按照视频方式操作。由于服务器昂贵,资源有限,生产环境的配置为2C 8G,所以服务比较慢用户体验一般,若想测试性能,请在本地部署
视频地址:https://www.bilibili.com/video/BV1YY4y147jz?spm_id_from=333.999.0.0
在线环境(演示):http://120.48.10.164:9528/ admin 123456
联系我:ycdtbs@163.com
Github: https://github.com/ycdtbs/massive_faceSearch/tree/main
在线环境说明
在线环境会收集大家数据,请勿上传敏感照片,项目测试数据集均来源于网络公开照片,利用Python脚本爬取,脚本存放于目录中
在线环境仅用于演示 请勿上传自己数据
在线环境仅用于演示 请勿上传自己数据
在线环境仅用于演示 请勿上传自己数据
在线环境仅用于演示 请勿上传自己数据
前言
大四毕业时做毕业设计,用到了百度云人脸识别的API,当时制作了一个demo发到Bilibli上,之后不少同学来问我,于是制作了一个利用虹软SDK的人脸识别的包含人脸库管理的一套服务,一年半来有不少朋友前来咨询人脸识别相关的问题,由于博主本人工作业务不涉及这部分,所以一直无心研究。最近北京疫情在家有了一些时间,利用了几天时间完善了基于虹软的代码。
首先说明一下上个版本的缺陷是什么,首先之前的人脸数据缓存在了Redis当中,当我们解析出特征值时,将数据缓存到redis中,进行逐个必对和判断,**优化的方式也只是单纯的利用多线程和虹软的人基本特征(性别、年龄)**等进行分库,几百个人脸时还好,在上千个人脸时就会出现非常明显的延迟,用户体验效率非常低,因此基于上个版本只满足部分同学的毕业设计、小组作业的场景。偶然在工作中了解到了向量搜索引擎,于是考虑是否可以结合虹软的人脸识别SDK提取特征向量,然后进行分析处理。由于这个demo主要是搭建一个大规模人脸搜索和识别服务的demo,因此没有工程化,系统设计的也比较冗余,没有详细的功能设计,基本是博主想到什么做什么。最后跪求一个 STAR 重要的事情说三遍 STAR STAR STAR
系统架构
功能设计
系统功能模块较为简单,主要功能就是新增人脸和人脸搜索两个功能,其中新增人脸使用页面上传和压缩包批量上传两个方式,压缩包上传时文件名称为用户名,下面主要说明人脸搜索的功能流程
Milvues
在介绍前需要说明一下Mulvus
Milvus 向量数据库能够帮助用户轻松应对海量非结构化数据(图片 / 视频 / 语音 / 文本)检索。单节点 Milvus 可以在秒内完成十亿级的向量搜索
因此虹软的SDK只能提取向量及对比的功能,在大规模人脸识别中,需要搜索引擎对于人脸数据进行初步筛选到一个较小的范围后在利用虹软的SDK进行测试,值得一提的是,博主多次测试后Milvues返回的匹配率足以满足人脸匹配的要求,Milvus的安装部署和使用文档参考 https://milvus.io/cn/docs/v2.0.x
特别说明的是虹软提取的数组是一个经过归一后的1032长度的byte数组,我们需要对数组进行转换,去除前8位的版本号,并将1024长度的byte转为256长度的float向量,这部分可以利用Arrays提供的方法进行转换,代码中也有相应的工具类
人脸上传(单张)
人脸上传(批量)
批量上传采用本地打包压缩上传到服务器,后台进程进行解压,放到队列中处理,处理结果存储在ES数据库中,实时结果及处理进度通过Websocket发送至前台
人脸搜索
技术架构
前端框架
前端使用了Vue admin temlate 及 Element UI
后端框架
后端框架主要是SpringBoot
数据库
- mysql:存储用户信息,所有的数据以Mysql数据为准
- Elasticsearch:由于批量上传操作是异步的,用ES来收集日志并分析热点数据、成功数据、失败数据(当前版本未实现)
- InfluxDB:用于涉及到数据源较多,事务处理过于麻烦,架构设计中以Mysql中的数据为准,以Mysql数据进行数据同步
- 阿里云OSS:负责存储裁切后的人脸照片,负责前台展示及缓存失效时重新加载
- Milvues:项目的核心数据库向量搜索引擎
中间件
- ActiveMq:由于大规模人脸搜索服务需要大量的照片,一个个手动上传不现实,因此开发了批量上传的功能,需要ActiveMq进行异步上传
前后端交互
- restful:前后端交互主要使用restful接口
- websocket:负责将后端处理照片的过程及照片实时显示在前端
安装部署
前端
.env.development 文件配置后端交互地址,只需要修改所有的IP+端口 其他路径不要改变
# just a flag ENV = 'development' # base api VUE_APP_BASE_API = 'http://127.0.0.1:8080/' #VUE_APP_BASE_API = 'http://120.48.10.164:8080/'# uploadFile VUE_APP_BASE_API_UPFILE = 'http://127.0.0.1:8080/file/getImageUrl'VUE_APP_BASE_API_UPFILE_LIST = 'http://127.0.0.1:8080/file/getListImageUrl'VUE_APP_BASE_API_WEBSOCKET = 'ws://127.0.0.1:8080/api/pushMessage/'VUE_APP_BASE_API_UPFILE = 'http://120.48.10.164:8080/file/getImageUrl'#VUE_APP_BASE_API_UPFILE_LIST = 'http://120.48.10.164:8080/file/getListImageUrl'#VUE_APP_BASE_API_WEBSOCKET = 'ws://120.48.10.164:8080/api/pushMessage/'
VUE_APP_BASE_API:后端服务接口
VUE_APP_BASE_API_UPFILE:单个文件上传地址
VUE_APP_BASE_API_UPFILE_LIST:文件列表上传地址
VUE_APP_BASE_API_WEBSOCKET:Websocket地址
运行
npm install npm run dev 服务端口:ip:9528
后端配置
- application.yml 主要是服务地址
- 修改Redis配置
- 修改Mysql配置
- 修改ActiveMq配置
- 修改Milvues配置
- 修改阿里云对象存储地址
- uploadFile配置本地缓存路径,主要是压缩包上传时需要用到
- FaceEngineConfig 类
- 配置虹软SDK的APID、SK,引擎地址
服务
- mysql
- redis
- activeMq
- Elasticsearch(此版本不用安装)
- InfluxDB(此版本不用安装)
- Milvus
数据库
- 执行face.sql
人脸数据
- 利用python脚本自行爬取
核心方法
FaceEngineConfig 类
类的主要功能是配置faceEngine的认证配置信息
public class FaceEngineConfig {public static final String APPID = "";public static final String SDKKEY = "";//public static final String SDKKEY = "";//linuxpublic static final String LIB = "D:\\face_web\\ArcSoft_ArcFace_Java_Windows_x64_V3.0\\libs\\WIN64";//public static final String LIB = ""; // linux}
FaceEnginePoolFactory 引擎对象工厂类
引擎对象工厂类,负责维护一个对象池
@Log4j2
@Component
public class FaceEnginePoolFactory extends BasePooledObjectFactory<FaceEngine> {/*** 在对象池中创建对象* @return* @throws Exception*/@Overridepublic FaceEngine create() throws Exception {FaceEngine faceEngine = new FaceEngine(FaceEngineConfig.LIB);//激活引擎int errorCode = faceEngine.activeOnline(FaceEngineConfig.APPID, FaceEngineConfig.SDKKEY);if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {System.out.println("引擎激活失败");}ActiveFileInfo activeFileInfo=new ActiveFileInfo();errorCode = faceEngine.getActiveFileInfo(activeFileInfo);if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {System.out.println("获取激活文件信息失败");}//引擎配置EngineConfiguration engineConfiguration = new EngineConfiguration();engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);engineConfiguration.setDetectFaceMaxNum(10);engineConfiguration.setDetectFaceScaleVal(16);//功能配置FunctionConfiguration functionConfiguration = new FunctionConfiguration();functionConfiguration.setSupportAge(true);functionConfiguration.setSupportFace3dAngle(true);functionConfiguration.setSupportFaceDetect(true);functionConfiguration.setSupportFaceRecognition(true);functionConfiguration.setSupportGender(true);functionConfiguration.setSupportLiveness(true);functionConfiguration.setSupportIRLiveness(true);engineConfiguration.setFunctionConfiguration(functionConfiguration);//初始化引擎errorCode = faceEngine.init(engineConfiguration);if (errorCode != ErrorInfo.MOK.getValue()) {log.error("初始化引擎失败");}return faceEngine;}/*** 包装对象* @param faceEngine* @return*/@Overridepublic PooledObject<FaceEngine> wrap(FaceEngine faceEngine) {return new DefaultPooledObject<>(faceEngine);}/*** 销毁对象* @param faceEngine 对象池* @throws Exception 异常*/@Overridepublic void destroyObject(PooledObject<FaceEngine> faceEngine) throws Exception {super.destroyObject(faceEngine);}/*** 校验对象是否可用* @param faceEngine 对象池* @return 对象是否可用结果,boolean*/@Overridepublic boolean validateObject(PooledObject<FaceEngine> faceEngine) {return super.validateObject(faceEngine);}/*** 激活钝化的对象系列操作* @param faceEngine 对象池* @throws Exception 异常信息*/@Overridepublic void activateObject(PooledObject<FaceEngine> faceEngine) throws Exception {super.activateObject(faceEngine);}/*** 钝化未使用的对象* @param faceEngine 对象池* @throws Exception 异常信息*/@Overridepublic void passivateObject(PooledObject<FaceEngine> faceEngine) throws Exception {super.passivateObject(faceEngine);}}
faceUtils 人脸识别工具类
核心的人脸识别类,负责提取特征值、截取人脸、特征值对比
public class faceUtils {private GenericObjectPool<FaceEngine> faceEngineGenericObjectPool;faceUtils(){// 对象池工厂FaceEnginePoolFactory personPoolFactory = new FaceEnginePoolFactory();// 对象池配置GenericObjectPoolConfig<FaceEngine> objectPoolConfig = new GenericObjectPoolConfig<>();objectPoolConfig.setMaxTotal(5);AbandonedConfig abandonedConfig = new AbandonedConfig();abandonedConfig.setRemoveAbandonedOnMaintenance(true); //在Maintenance的时候检查是否有泄漏abandonedConfig.setRemoveAbandonedOnBorrow(true); //borrow 的时候检查泄漏abandonedConfig.setRemoveAbandonedTimeout(10); //如果一个对象borrow之后10秒还没有返还给pool,认为是泄漏的对象// 对象池faceEngineGenericObjectPool = new GenericObjectPool<>(personPoolFactory, objectPoolConfig);faceEngineGenericObjectPool.setAbandonedConfig(abandonedConfig);faceEngineGenericObjectPool.setTimeBetweenEvictionRunsMillis(5000); //5秒运行一次维护任务log.info("引擎池开启成功");}/*** 人脸检测** @param fileInputStream* @return*/public List<FaceInfo> faceFind(InputStream fileInputStream) throws IOException {FaceEngine faceEngine = null;try {faceEngine = faceEngineGenericObjectPool.borrowObject();ImageInfo imageInfo = getRGBData(fileInputStream);List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();int errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);return faceInfoList;} catch (Exception e) {log.error("出现了异常");e.printStackTrace();return new ArrayList<FaceInfo>();} finally {fileInputStream.close();// 回收对象到对象池if (faceEngine != null) {faceEngineGenericObjectPool.returnObject(faceEngine);}}}/*** 人脸截取** @param fileInputStream* @param rect* @return*/public String faceCrop(InputStream fileInputStream, Rect rect) {try {ByteArrayOutputStream stream = new ByteArrayOutputStream();BufferedImage bufImage = ImageIO.read(fileInputStream);int height = bufImage.getHeight();int width = bufImage.getWidth();int top = rect.getTop();int bottom = rect.getBottom();int left = rect.getLeft();int right = rect.getRight();//System.out.println(top + "-" + bottom + "-" + left + "-" + right);try {BufferedImage subimage = bufImage.getSubimage(left, top, right - left, bottom - left);ImageIO.write(subimage, "png", stream);String base64 = Base64.encode(stream.toByteArray());return base64;}catch (Exception e){return null;}finally {stream.close();fileInputStream.close();}} catch (IOException e) {e.printStackTrace();}finally {}return null;}/*** 人脸特征值提取*/public byte[] faceFeature(InputStream fileInputStream,FaceInfo faceInfo) throws IOException {FaceEngine faceEngine = null;FaceFeature faceFeature = new FaceFeature();try {faceEngine = faceEngineGenericObjectPool.borrowObject();ImageInfo imageInfo = getRGBData(fileInputStream);int errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfo, faceFeature);byte[] featureData = faceFeature.getFeatureData();return featureData;} catch (Exception e) {log.error("出现了异常");e.printStackTrace();return new byte[0];} finally {fileInputStream.close();// 回收对象到对象池if (faceEngine != null) {faceEngineGenericObjectPool.returnObject(faceEngine);}}}/*** 人脸对比*/public float faceCompared(byte [] source,byte [] des) throws IOException {FaceEngine faceEngine = null;try {faceEngine = faceEngineGenericObjectPool.borrowObject();FaceFeature targetFaceFeature = new FaceFeature();targetFaceFeature.setFeatureData(source);FaceFeature sourceFaceFeature = new FaceFeature();sourceFaceFeature.setFeatureData(des);FaceSimilar faceSimilar = new FaceSimilar();faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);float score = faceSimilar.getScore();return score;} catch (Exception e) {log.error("出现了异常");e.printStackTrace();return 0;} finally {// 回收对象到对象池if (faceEngine != null) {faceEngineGenericObjectPool.returnObject(faceEngine);}}}
milvusOperateUtils Milvues工具类
public class milvusOperateUtils {private GenericObjectPool<MilvusServiceClient> milvusServiceClientGenericObjectPool; // 管理链接对象的池子// https://milvus.io/cn/docs/v2.0.x/load_collection.mdprivate final int MAX_POOL_SIZE = 5;private milvusOperateUtils() {// 私有构造方法创建一个池// 对象池工厂MilvusPoolFactory milvusPoolFactory = new MilvusPoolFactory();// 对象池配置GenericObjectPoolConfig<FaceEngine> objectPoolConfig = new GenericObjectPoolConfig<>();objectPoolConfig.setMaxTotal(8);AbandonedConfig abandonedConfig = new AbandonedConfig();abandonedConfig.setRemoveAbandonedOnMaintenance(true); //在Maintenance的时候检查是否有泄漏abandonedConfig.setRemoveAbandonedOnBorrow(true); //borrow 的时候检查泄漏abandonedConfig.setRemoveAbandonedTimeout(MAX_POOL_SIZE); //如果一个对象borrow之后10秒还没有返还给pool,认为是泄漏的对象// 对象池milvusServiceClientGenericObjectPool = new GenericObjectPool(milvusPoolFactory, objectPoolConfig);milvusServiceClientGenericObjectPool.setAbandonedConfig(abandonedConfig);milvusServiceClientGenericObjectPool.setTimeBetweenEvictionRunsMillis(5000); //5秒运行一次维护任务log.info("milvus 对象池创建成功 维护了" + MAX_POOL_SIZE + "个对象");}// 创建一个Collection 类似于创建关系型数据库中的一张表private void createCollection(String collection) {MilvusServiceClient milvusServiceClient = null;try {// 通过对象池管理对象milvusServiceClient = milvusServiceClientGenericObjectPool.borrowObject();FieldType fieldType1 = FieldType.newBuilder().withName(faceMilvus.Field.USER_NAME).withDescription("用户名").withDataType(DataType.Int64).build();FieldType fieldType2 = FieldType.newBuilder().withName(faceMilvus.Field.USER_CODE).withDescription("编号").withDataType(DataType.Int64).withPrimaryKey(true).withAutoID(false).build();FieldType fieldType3 = FieldType.newBuilder().withName(faceMilvus.Field.FEATURE).withDescription("特征向量").withDataType(DataType.FloatVector).withDimension(faceMilvus.FEATURE_DIM).build();CreateCollectionParam createCollectionReq = CreateCollectionParam.newBuilder().withCollectionName(collection).withDescription("人脸特征向量库").withShardsNum(2).addFieldType(fieldType2).addFieldType(fieldType1).addFieldType(fieldType3).build();R<RpcStatus> result = milvusServiceClient.createCollection(createCollectionReq);log.info("创建结果" + result.getStatus() + "0 为成功");} catch (Exception e) {e.printStackTrace();} finally {// 回收对象到对象池if (milvusServiceClient != null) {milvusServiceClientGenericObjectPool.returnObject(milvusServiceClient);}}}public void loadingLocation(String collection) {MilvusServiceClient milvusServiceClient = null;try {// 通过对象池管理对象milvusServiceClient = milvusServiceClientGenericObjectPool.borrowObject();R<RpcStatus> rpcStatusR = milvusServiceClient.loadCollection(LoadCollectionParam.newBuilder().withCollectionName(collection).build());log.info("加载结果" + rpcStatusR);} catch (Exception e) {e.printStackTrace();} finally {// 回收对象到对象池if (milvusServiceClient != null) {milvusServiceClientGenericObjectPool.returnObject(milvusServiceClient);}}}public void freedLoaction(String collection) {MilvusServiceClient milvusServiceClient = null;try {// 通过对象池管理对象milvusServiceClient = milvusServiceClientGenericObjectPool.borrowObject();R<RpcStatus> rpcStatusR = milvusServiceClient.releaseCollection(ReleaseCollectionParam.newBuilder().withCollectionName(collection).build());log.info("加载结果" + rpcStatusR);} catch (Exception e) {e.printStackTrace();} finally {// 回收对象到对象池if (milvusServiceClient != null) {milvusServiceClientGenericObjectPool.returnObject(milvusServiceClient);}}}// 删除一个Collectionprivate void delCollection(String collection) {MilvusServiceClient milvusServiceClient = null;try {// 通过对象池管理对象milvusServiceClient = milvusServiceClientGenericObjectPool.borrowObject();R<RpcStatus> book = milvusServiceClient.dropCollection(DropCollectionParam.newBuilder().withCollectionName(collection).build());log.info("删除" + book.getStatus() + " 0 为成功");} catch (Exception e) {e.printStackTrace();} finally {// 回收对象到对象池if (milvusServiceClient != null) {milvusServiceClientGenericObjectPool.returnObject(milvusServiceClient);}}}// 插入数据 和对应的字段相同public long insert(String collectionName, String partitionName, List<Long> userName, List<Long> userCode, List<List<Float>> feature) {MilvusServiceClient milvusServiceClient = null;try {// 通过对象池管理对象milvusServiceClient = milvusServiceClientGenericObjectPool.borrowObject();List<InsertParam.Field> fields = new ArrayList<>();fields.add(new InsertParam.Field(faceMilvus.Field.USER_NAME, DataType.Int64, userName));fields.add(new InsertParam.Field(faceMilvus.Field.USER_CODE, DataType.Int64, userCode));fields.add(new InsertParam.Field(faceMilvus.Field.FEATURE, DataType.FloatVector, feature));InsertParam insertParam = InsertParam.newBuilder().withCollectionName(collectionName).withPartitionName(partitionName).withFields(fields).build();R<MutationResult> insertResult = milvusServiceClient.insert(insertParam);if (insertResult.getStatus() == 0) {return insertResult.getData().getIDs().getIntId().getData(0);} else {log.error("特征值上传失败 加入失败队列稍后重试");}} catch (Exception e) {e.printStackTrace();return 0;} finally {// 回收对象到对象池if (milvusServiceClient != null) {milvusServiceClientGenericObjectPool.returnObject(milvusServiceClient);}}return 0;}// 根据向量搜索数据public List<?> searchByFeature(String collection,List<List<Float>> search_vectors) {MilvusServiceClient milvusServiceClient = null;try {// 通过对象池管理对象milvusServiceClient = milvusServiceClientGenericObjectPool.borrowObject();List<String> search_output_fields = Arrays.asList(faceMilvus.Field.USER_CODE);SearchParam searchParam = SearchParam.newBuilder().withCollectionName(collection).withPartitionNames(Arrays.asList("one")).withMetricType(MetricType.L2).withOutFields(search_output_fields).withTopK(faceMilvus.SEARCH_K).withVectors(search_vectors).withVectorFieldName(faceMilvus.Field.FEATURE).withParams(faceMilvus.SEARCH_PARAM).build();R<SearchResults> respSearch = milvusServiceClient.search(searchParam);if (respSearch.getStatus() == 0){SearchResultsWrapper wrapperSearch = new SearchResultsWrapper(respSearch.getData().getResults());List<?> fieldData = wrapperSearch.getFieldData(faceMilvus.Field.USER_CODE, 0);return fieldData;}} catch (Exception e) {e.printStackTrace();return new ArrayList<>();} finally {// 回收对象到对象池if (milvusServiceClient != null) {milvusServiceClientGenericObjectPool.returnObject(milvusServiceClient);}}return new ArrayList<>();}public static void main(String[] args) {milvusOperateUtils milvusOperateUtils = new milvusOperateUtils();milvusOperateUtils.createCollection("face_home");//milvusOperateUtils.delCollection("");}
}
相关文档
虹软
https://ai.arcsoft.com.cn/
Milvus
https://milvus.io/cn/docs/v2.0.x/create_collection.md
SpringBoot 基于向量搜索引擎及虹软人脸识别SDK的大规模人脸搜索相关推荐
- 美狐人脸识别SDK技术,人脸检测SDK技术达到实时美颜滤镜的效果
为了实现高颜值又不失真的直播实时美颜滤镜的功能,技术关键点主要涉及人脸识别SDK技术和人脸检测SDK技术,对特征点定位与跟踪.特效处理.美白和磨皮四个方面.下面依次介绍这四个主要功能点: 1.美狐人脸 ...
- (三)、从零开始搭建人脸识别服务之大规模人脸识别
人脸识别服务需要包括以下几个功能模块: 1.人脸检测和人脸校正模块 2.人脸特征提取模块 3.人脸特征匹配模块 4.人脸识别结果计算模块 前两篇文章中分别介绍了人脸检测和人脸特征提取,这篇文章简要介绍 ...
- 嵌入式linux人脸识别sdk,嵌入式前端人脸识别SDK - AID.Face 正式上线丨OPEN AI
原标题:嵌入式前端人脸识别SDK - AID.Face 正式上线丨OPEN AI AID.Face是以Tengine/HCL为平台的嵌入式前端人脸识别SDK,可在现有SoC上流畅的使用人脸识别功能,特 ...
- 借助百度云平台人脸识别sdk完成网页人脸识别登录demo
最近在浏览百度云平台人工智能相关产品时,萌生了做一个网页人脸识别登录的demo. 以下是前端代码: 实现在浏览器调用摄像头,捕捉图片后上传到服务器验证. <!DOCTYPE html> & ...
- android 人脸识别边框_android Arcface人脸识别框/人脸抓拍框/人脸追踪框
为什么要改? 先来看看sdk demo中提供的人脸框样式,这个框看上去并不是非常美观(个人觉得) 再看看下面这个框是不是就要顺眼一点 怎么换? 先来看看原始的画法: @Override public ...
- java 基于虹软离线人脸识别SDK 2.0 最新版
虹软人脸识别SDK之Java版,支持SDK 1.1+,以及当前最新版本2.0,滴滴,抓紧上车! JDK SDK Win release license status 前言 由于业务需求,最近跟人脸识别 ...
- 【javaCV基于虹软人脸识别demo添加电脑摄像头人脸识别(图片保存,视频保存,摄像头显示等 )(附源码)】
javaCV基于虹软人脸识别demo添加电脑摄像头人脸识别(图片保存,视频保存,摄像头显示等 )(附源码) 文章目录 javaCV基于虹软人脸识别demo添加电脑摄像头人脸识别(图片保存,视频保存,摄 ...
- 虹软人脸识别SDK接入Milvus实现海量人脸快速检索
虹软人脸识别SDK接入Milvus实现海量人脸快速检索 背景 虹软SDK及Milvus简介 开发环境 虹软人脸识别SDK使用简介 Milvus环境搭建 快速检索实现 人脸识别流程简介 快速检索 虹软S ...
- 虹软人脸识别 - 采用数据库存取人脸特征数据
虹软人脸识别 - 采用数据库存取人脸特征数据 前几天有个朋友遇到了个问题,他在使用虹软的人脸识别引擎时,想更换一下人脸识别的存储方式,原本demo中使用的是文件的方式进行存储,而他想要通过数据库的方式 ...
最新文章
- 企业号、订阅号、服务号的一此区别
- 常用的几种大数据架构剖析
- 贼好用的 Java 工具类库,GitHub 星标 10k+,你在用吗?
- android 打印线程信息
- 如何用c语言从txt文件中读取数据
- Spring Security记住我功能之潜在的账号盗取风险
- 论文解读丨文档结构分析
- 使用Oracle 11g新特性 Active Database Duplication 搭建Dataguard环境
- java_day01
- php源码 自定义字段,wordpress主题制作:设置自定义选项字段
- ●BZOJ 2393 Cirno的完美算数教室
- MybatisPlus的CRUD操作
- cass转换jpg_【转】南方CASS作原有地形图数字化--对扫描栅格图像进行校正及矢量化...
- idea社区版创建springboot_idea社区版+spring boot
- 经典计算机书籍【转贴
- MYSQL之错误代码----mysql错误代码与JAVA实现
- 2021年自动化预推免面试经历记录与总结--持续更新
- python编写MySQL数据库查询/操作软件代码
- Unity UGUI图文混排源码--优化版
- 欢乐颂之鸿蒙系统,杨烁现实中的老婆 小包总抱得美人归